panic() / recover()
panic() is a built-in Go function that triggers a runtime error, used to represent serious problems that cannot be handled through normal error handling (returning an error value). recover() is a function used inside a defer to catch a panic and return to normal execution.
Syntax
// Triggers a panic.
panic(value) // You can pass a string, an error, or any value.
// Catches a panic with recover (only valid inside a defer).
defer func() {
if r := recover(); r != nil {
// Recovered from panic. r is the value passed to panic().
fmt.Println("caught panic:", r)
}
}()
// When a panic occurs, the following steps happen in order:
// 1. The remaining code in the current function is skipped.
// 2. Registered defers are executed (recover can catch the panic here).
// 3. If not caught, the panic propagates to the caller.
// 4. Eventually, the program crashes and prints a stack trace.
Functions
| Function | Description |
|---|---|
| panic(v) | Triggers a runtime error. You can pass any value as the argument. |
| recover() | Catches the panic value inside a defer and resumes normal execution. Returns nil if no panic is in progress. |
Sample Code
package main
import "fmt"
// safeDiv uses recover to catch a panic and return an error instead.
func safeDiv(a, b int) (result int, err error) {
defer func() {
if r := recover(); r != nil {
// Catch the panic and return it as an error.
err = fmt.Errorf("recovered from panic: %v", r)
}
}()
// When b == 0, the Go runtime triggers a panic.
result = a / b
return
}
// An example of a panic propagating up the call stack.
func level3() {
panic("panic occurred in level3")
}
func level2() {
level3()
}
func level1() {
defer func() {
if r := recover(); r != nil {
fmt.Println("caught panic in level1:", r)
}
}()
level2() // The panic from level3 propagates here and is caught by the defer.
}
// An example of using panic for invalid arguments (returning an error is usually preferred).
func mustPositive(n int) int {
if n <= 0 {
panic(fmt.Sprintf("a positive integer is required, but got %d", n))
}
return n
}
func main() {
// safeDiv: catches a divide-by-zero panic with recover.
result, err := safeDiv(10, 2)
fmt.Printf("10 / 2 = %d, err = %v\n", result, err)
result, err = safeDiv(10, 0)
fmt.Printf("10 / 0 = %d, err = %v\n", result, err)
fmt.Println()
// Example of panic propagation and recover.
level1()
fmt.Println()
// mustPositive
fmt.Println("positive integer:", mustPositive(5))
// Calling mustPositive(-1) would cause a panic and crash the program.
}
Notes
In Go, returning an error value is the recommended approach for error handling. Use panic() only for serious situations where the program cannot continue — such as initialization failures or logically invalid states. recover() must always be called inside a defer. When a panic occurs inside a library, it is idiomatic Go to catch it with recover at the public API boundary and return it as an error.
Using panic for ordinary error handling is not recommended. A panic affects the entire call stack, and a panic in one goroutine does not propagate to other goroutines, so each goroutine must handle recovery individually.
For how panic works with defer, see defer. For standard error handling, see error type / errors package.
If you find any errors or copyright issues, please contact us.