Hard15 minGo Fundamentals
UpdatedAug 4, 2026
Edit

Defer Panic and Recover

CONCEPTS:Go Defer Panic and Recover

Question Variations

  • "When do deferred calls run, and in what order?"
  • "Should a Go API use panic for expected failures?"
  • "Why does `recover` not catch a panic from another goroutine?"
  • "What value does a deferred closure observe?"

Why This Is Asked

This topic tests whether you can distinguish ordinary error handling from exceptional failure and reliably clean up resources. It also exposes misconceptions about defer timing and the limited scope in which a panic can be recovered.

Key Concepts

  • Deferred calls run when the surrounding function returns, in last-in-first-out order.
  • Arguments to a deferred call are evaluated when defer executes.
  • A panic unwinds the current goroutine’s stack while running deferred calls.
  • recover only works when directly invoked by a deferred function in the panicking goroutine.

Question Variations

  • “When do deferred calls run, and in what order?”
  • “Should a Go API use panic for expected failures?”
  • “Why does recover not catch a panic from another goroutine?”
  • “What value does a deferred closure observe?”

Answers by Technology

+ Add Variant
GoImprove this answer ✏️

Expected Answer (Go 1.26.5)

defer schedules a call to run when the current function exits, whether it exits normally or while a panic unwinds. Multiple deferred calls run in reverse order. The arguments in defer f(x) are evaluated immediately, whereas a deferred closure can read a later value of an outer variable.

panic is for unrecoverable or violated-invariant situations, not routine failures that should be returned as error. recover can stop a panic only when it is called directly by a deferred function in the same goroutine.

package main

import "fmt"

func safeDivide(a, b int) (result int, err error) {
	defer func() {
		if value := recover(); value != nil {
			err = fmt.Errorf("divide failed: %v", value)
		}
	}()

	if b == 0 {
		panic("zero divisor")
	}
	return a / b, nil
}

func main() {
	_, err := safeDivide(10, 0)
	fmt.Println(err)
}

Recovery is usually reserved for a narrow boundary, such as preventing a server handler from crashing the whole process, where the program can log and report a controlled failure.

Why It Matters

Using defer correctly prevents leaked files, locks, and spans. Keeping panics exceptional retains clear error contracts and prevents recovery from concealing programmer defects.

Common Mistakes

  • Using panic instead of returning expected validation or I/O errors: This makes normal control flow hard for callers to handle.
  • Expecting recover in one goroutine to catch another’s panic: Panics are isolated to the goroutine where they occur.
  • Assuming deferred arguments see later variable changes: Non-closure arguments are evaluated at the defer statement.

Follow-up Questions

  • In what order do multiple deferred calls run? (Answer: Last-in-first-out.)
  • Why might a named return value be used with a deferred function? (Answer: The deferred function can inspect or modify the named result before the function returns.)