← Go, End to End

Go, End to End

Defer, Panic, and Recover

These three are related but solve different problems, and confusing them is one of the more common ways newcomers write Go that technically works but reads oddly to anyone else.

defer

defer schedules a function call to run when the surrounding function returns, regardless of how it returns (normal return, or a panic unwinding through it). The classic use is guaranteeing cleanup happens next to the code that created the thing needing cleanup, instead of scattered at every possible exit point:

go · live, editable, runnable

Multiple defers in one function run in LIFO order, last deferred, first executed, which matters when the cleanups have a dependency order (close the file you opened last, first):

go · live, editable, runnable

In real code, defer is how you close files (defer f.Close()), unlock mutexes (defer mu.Unlock()), and generally pair "acquire" with "release" right next to each other instead of trusting every return path to remember.

panic

panic is Go's mechanism for "this program cannot continue correctly", and it's deliberately distinct from error. An error is an expected, recoverable outcome your caller should handle (a file not found, a network timeout). A panic is for programmer mistakes and truly unrecoverable states: an index out of range, a nil map write, an explicit panic("invariant violated") when your own code detects it's in a state that should be impossible.

Mixing these up is the actual pitfall: don't panic for things a caller could reasonably expect and handle (that's what error is for), and don't return an error for a genuine programming bug you'd rather crash loudly on during development.

go · live, editable, runnable

recover

recover stops a panic from propagating, but only when called directly inside a deferred function. Called anywhere else, it does nothing and returns nil.

go · live, editable, runnable
Recover at most at a goroutine or request boundary (an HTTP handler, a worker goroutine's top level), so one bad input can't take down the whole process. Don't use panic/recover as a general substitute for normal error returns, that's not what it's for and it makes control flow much harder to follow.

Try it yourself: write a function that recovers from a panic caused by indexing past the end of a slice, and returns a normal error instead. Confirm the program keeps running afterward instead of crashing.