When is it appropriate to panic instead of returning an error?
Question 305MediumGo 1.22 to 1.25
Panic when there is a programmer error or an impossible state that the caller can't reasonably handle:
- Violated invariants, such as an unreachable
defaultin an exhaustive switch, or a nil dependency passed to a constructor. Musthelpers for static inputs at initialization:regexp.MustCompile,template.Must. The input is a constant, so failure is a bug.- Failed startup when the program can't run at all. Even then,
log.Fatalor returning an error fromrun()is often cleaner.
Don't panic for anything that can happen in normal operation: bad user input, I/O, network or not-found conditions. A library should almost never let a panic escape its public API.
func MustParse[T any](s string, parse func(string) (T, error)) T {
v, err := parse(s)
if err != nil {
panic(fmt.Sprintf("MustParse(%q): %v", s, err))
}
return v
}
var port = MustParse("8080", strconv.Atoi)
An accepted exception: using panic/recover internally to unwind deep recursion, as encoding/json and text/template do, and converting the panic back to an error before returning to the caller. Recover only your own sentinel panic type, and re-panic anything else.
More on Error Handling & panics
- Q303When is
err == ErrXwrong, and why can comparing errors with==panic? - Q304When should you wrap an error and when should you not? How do you handle errors at package boundaries?
- Q306What does this print? (Rules of
recover) - Q307A goroutine panics. Can a
recoverinmaincatch it? How do you protect background goroutines? - Q308What does this print? (Defer order during panic)
- Q309How do you convert a panic into an error returned from a function?