panic, recover, and Failure Modes

Overview

panic and recover handle unrecoverable errors. Unlike normal errors, panics crash the program unless recovered.

When to Panic

Appropriate: - Programmer errors (bugs) - Impossible conditions - Failed invariants - During initialization

Avoid for: - Expected errors (file not found, network timeout) - User input validation - Anything recoverable

Panic

func divide(a, b int) int {
    if b == 0 {
        panic("division by zero")  // Terminates program
    }
    return a / b
}

Common Panic Sources

// nil pointer dereference
var p *int
*p = 1  // panic

// Index out of range
arr := []int{1, 2}
arr[10]  // panic

// Invalid type assertion
var i interface{} = "string"
i.(int)  // panic

Recover

Recover catches panics in deferred functions:

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

    dangerousOperation()
    return nil
}

HTTP Server Pattern

func handler(w http.ResponseWriter, r *http.Request) {
    defer func() {
        if err := recover(); err != nil {
            log.Printf("panic: %v\n%s", err, debug.Stack())
            http.Error(w, "Internal Server Error", 500)
        }
    }()

    // Handle request
}

Panic vs Error

// Return error for expected failures
func ReadFile(name string) ([]byte, error) {
    if !exists(name) {
        return nil, ErrNotFound  // Expected case
    }
    // ...
}

// Panic for bugs
func MustCompile(pattern string) *Regexp {
    r, err := Compile(pattern)
    if err != nil {
        panic(err)  // Invalid pattern is programmer error
    }
    return r
}

Summary

Keyword Purpose
panic Unrecoverable error (crash)
recover Catch panic in defer
error Expected, recoverable failures
Use panic for Use error for
Bugs Expected failures
Invariant violations User/external input
Initialization failures I/O, network errors