Errors · 3 MIN READ

panic is for bugs, not for failures

Say which of two situations deserves a panic.

A file that will not open is a failure: it is expected, the caller can do something about it, and it is an error value. An index past the end of a slice is a bug: the program's own logic is wrong, and continuing would be worse than stopping. Go draws that line deliberately, and a library that panics on bad input has drawn it in the wrong place.

recover exists, and its honest use is narrow: stopping one request from taking down a server, at the boundary, before returning an ordinary error. It is not a catch block, and using it as one hides the bug that caused it.

SEE THE IDEA

Ordinary failures and broken invariants have different exits

  1. 01

    Expected failure

    go
    return err

    The caller decides how to handle it

  2. 02

    Broken invariant

    go
    panic("invalid state")

    Stops normal execution in this goroutine

  3. 03

    Cleanup

    go
    defer cleanup()

    Runs while the stack unwinds

Panic is an exceptional control flow, not a replacement for an error result.

In practice

Return errors for invalid input, missing files and canceled operations that callers can reasonably expect. Reserve panic for contracts that cannot continue safely, or for a deliberate internal boundary that will recover. An unrecovered panic terminates the program.

Watch out

A deferred recover in one goroutine cannot catch a panic that happens in another goroutine.

Official reference ↗

Read and predict

go
package main

import "fmt"

func safe(work func()) (err error) {
	defer func() {
		if r := recover(); r != nil {
			err = fmt.Errorf("recovered: %v", r)
		}
	}()
	work()
	return nil
}

func main() {
	fmt.Println(safe(func() { fmt.Println("fine") }))
	fmt.Println(safe(func() { panic("bad state") }))
}

What does this print? Note that err is a named return.

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.