Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

recover is a built-in Go function that intercepts and halts the unwinding of the call stack during a panic, allowing a program to regain normal execution flow. It is exclusively effective when executed directly by a deferred function within the panicking goroutine.

Function Signature

func recover() any
recover returns an empty interface (any). In most cases, the value returned is the exact argument that was passed to the panic() call that initiated the stack unwinding. However, as an exception introduced in Go 1.21, if panic(nil) is called, recover returns a *runtime.PanicNilError rather than the exact nil argument.

Execution Mechanics

  1. Normal Execution: If recover is called during the normal execution of a program (i.e., no panic is currently unwinding the stack), it evaluates to nil and produces no side effects.
  2. Panic State: When a panic is triggered, Go halts standard control flow and begins popping frames off the call stack, executing any defer statements registered in those frames.
  3. Interception: If a deferred function invokes recover, the unwinding process is immediately terminated. The recover function captures the panic payload, clears the panic state, and allows the deferred function to complete.
  4. Resumption: After the deferred function containing the recover finishes, execution does not return to the point of the panic. Instead, the function that deferred the recovery terminates normally, and execution resumes at the call site of that function.

Syntax Visualization

func executionFrame() {
    // 1. Defer an anonymous function containing recover()
    defer func() {
        // 2. Assign the result of recover() to a variable
        if r := recover(); r != nil {
            // 3. The panic state is now cleared. 
            // 'r' contains the value "fatal error payload".
        }
    }()

    // 4. A panic is initiated, halting normal flow and triggering defers.
    panic("fatal error payload")
    
    // 5. This code is unreachable.
}

Technical Constraints

  • Goroutine Boundary: recover is strictly bound to the goroutine in which it is called. A recover in one goroutine cannot intercept a panic originating in a different goroutine.
  • Direct Call Frame Requirement: recover must be called directly by the deferred function (i.e., exactly one call frame deep from the defer mechanism). The requirement is based on the dynamic call stack, not static lexical scope. If recover is called by a nested function invoked by the deferred function, it will fail to intercept the panic and will return nil.
func validHandler() {
    recover() // Intercepts panic: called directly by the deferred function
}

func invalidHandler() {
    recover() // Returns nil: called two frames deep from the defer mechanism
}

func executionFrame() {
    // Valid: validHandler is the deferred function itself
    defer validHandler()

    // Invalid: the anonymous func is the deferred function, 
    // making invalidHandler's recover() one frame too deep.
    defer func() { 
        invalidHandler() 
    }()
    
    panic("fatal error payload")
}
  • Panic with Nil: Historically, calling panic(nil) would cause recover to return nil, making it difficult to distinguish between a recovered nil-panic and a non-panicking state. As of Go 1.21, calling panic(nil) causes recover to return a *runtime.PanicNilError rather than nil, ensuring that recover() != nil is a universally reliable check for an intercepted panic.
Master Go with Deep Grasping Methodology!Learn More