Errors · 3 MIN READ

recover belongs at the boundary

Turn a panic into an error without swallowing the rest of the program.

The Tour shows panic as a value and Effective Go keeps recover for a server boundary: one request, one goroutine, then an ordinary error back to the caller. recover only works inside a deferred function. A named result is how that error gets out — a return nil after work() would overwrite it.

A library that recovers in the middle of a calculation is hiding a bug. A process that recovers at main is pretending the program is still sound. The honest width is one unit of work you can abandon.

SEE THE IDEA

Recover must run inside deferred cleanup

  1. 01

    Boundary

    go
    defer func() { ... }()

    Registers a recovery function

  2. 02

    Unwind

    go
    panic(cause)

    Begins unwinding this goroutine

  3. 03

    Recover

    go
    r := recover()

    A direct call in the deferred function catches it

Recovery stops the unwind and lets the enclosing function return; it does not resume the panicking statement.

In practice

Put recovery at a boundary that can decide what a failed operation means, such as handling one request. Convert the recovered failure into an explicit result and record enough context to diagnose the bug. Do not hide unexpected failures in an apparently successful zero result.

Watch out

Calling recover through a non-deferred helper does not recover the panic. The recovering call must be made directly by the deferred function.

Official reference ↗

Work through the exercise

go
package main

// Guard runs work and returns an error if it panics. A clean
// run returns nil. Use recover in a defer.
func Guard(work func()) error {
	work()
	return nil
}

func main() {}
Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.