Go Panic and Recover
A panic is a failure that stops the normal flow of a function and unwinds the chain of calls. Recover is a built-in call that stops a panic and returns the value given to panic.
A deferred recover catches a panic
The deferred literal calls recover. It prints the value that panic was given.
package main
import "fmt"
func run() {
defer func() {
value := recover()
fmt.Println("Recovered:", value)
}()
panic("something broke")
}
func main() {
run()
}The program continues after a recover
task panics and its deferred literal recovers the value. Main prints its next line after task returns.
package main
import "fmt"
func task() {
defer func() {
value := recover()
fmt.Println("Recovered:", value)
}()
panic("task failed")
}
func main() {
task()
fmt.Println("Program continues")
}A panic in a helper is recovered in the caller
The deferred literal lives in caller, one frame above fail. The print line after the fail call never runs.
package main
import "fmt"
func fail() {
panic("helper failed")
}
func caller() {
defer func() {
value := recover()
fmt.Println("Recovered:", value)
}()
fail()
fmt.Println("After helper")
}
func main() {
caller()
}recover returns nil when nothing panicked
Both functions defer the same guard print. The calm one sees nil and the risky one sees a panic value.
package main
import "fmt"
func calm() {
defer func() {
value := recover()
fmt.Println("Recovered value is nil:", value == nil)
}()
fmt.Println("calm work")
}
func risky() {
defer func() {
value := recover()
fmt.Println("Recovered value is nil:", value == nil)
}()
panic("risk failed")
}
func main() {
calm()
risky()
}Example
package main
import "fmt"
func divide(a int, b int) (result int) {
defer func() {
value := recover()
if value != nil {
fmt.Println("Recovered:", value)
result = 0
}
}()
if b == 0 {
panic("division by zero")
}
return a / b
}
func main() {
fmt.Println(divide(10, 0))
fmt.Println(divide(10, 2))
}Key points
- Use panic with a value to start a panic on purpose.
- A panic climbs back through the calling functions as it unwinds.
- An unwinding panic runs the deferred calls of each function it leaves.
- Use recover inside a deferred function to stop a panic.
- recover returns the value that was passed to panic.
- recover returns nil when no panic is happening.
- After a recover, the enclosing function returns and the program continues.
In this example, divide panics when the second number is zero. The deferred literal recovers the panic value and prints it. It sets the named result to 0, so main prints 0 for that call. The second call divides 10 by 2 and prints 5.
Note
A panic that no function recovers ends the program.
Try it Yourself
Edit the code, then press Run.
Running is simulated · Go Playground
Exercise
Where must recover be called to stop a panic?