Go > Core Go Basics > Functions > Panic and recover

Panic and Recover in Go

This code demonstrates how to use panic and recover in Go to handle unexpected errors and prevent program crashes. It shows a simple scenario where a function panics due to an invalid index access, and how recover can be used to gracefully handle the panic and continue execution.

Basic Panic Example

This code showcases a basic example where the 'mightPanic' function might cause a panic if the supplied index is out of bounds for the array. When the 'panic' function is called, normal execution stops, and the program prints the panic message to standard error and terminates. Try running this to observe the panic.

package main

import (
	"fmt"
)

func mightPanic(index int) {
	arr := []int{1, 2, 3}
	fmt.Println("Accessing index:", index)
	if index >= len(arr) {
		panic("Index out of bounds!")
	}
	fmt.Println("Value at index:", arr[index])
}

func main() {
	mightPanic(0)
	mightPanic(5)
	mightPanic(1)
	fmt.Println("Program continues...")
}

Recovering from a Panic

This example demonstrates the use of 'recover'. The 'safeFunction' uses a 'defer' statement with an anonymous function that calls 'recover'. If 'mightPanic' panics, 'recover' will catch the panic, allowing the program to continue execution instead of crashing. Note that recover only works within the deferred function.

package main

import (
	"fmt"
)

func mightPanic(index int) {
	arr := []int{1, 2, 3}
	fmt.Println("Accessing index:", index)
	if index >= len(arr) {
		panic("Index out of bounds!")
	}
	fmt.Println("Value at index:", arr[index])
}

func safeFunction(index int) {
	defer func() {
		if r := recover(); r != nil {
			fmt.Println("Recovered from panic:", r)
		}
	}()
	mightPanic(index)
	fmt.Println("Continuing after mightPanic...")
}

func main() {
	safeFunction(0)
	safeFunction(5)
	safeFunction(1)
	fmt.Println("Program continues...")
}

Concepts Behind Panic and Recover

panic is a built-in function that stops the normal execution flow of a goroutine. When panic is called, deferred functions are executed in reverse order. recover is a built-in function that regains control of a panicking goroutine. It's only useful inside deferred functions. recover stops the panicking sequence by restoring normal execution and retrieves the error value passed to panic. If you call recover outside of a deferred function, it will not stop a panicking sequence. The return value of recover will be nil if the current goroutine is not panicking.

Real-Life Use Case

Panic and recover are useful when dealing with unexpected errors that should not normally happen in the application. Examples include accessing a configuration value that is expected to be present but is missing due to deployment issues, or handling unexpected input in a data processing pipeline. They can also be used to handle errors from libraries that might panic when encountering severe issues, allowing your application to gracefully recover and log the error rather than crashing. For example, handling malformed regular expressions or corrupted data files.

Best Practices

Prefer error handling with explicit return values over panic and recover for anticipated errors. Use panic sparingly, primarily for unrecoverable errors that indicate a serious problem. Always use recover within a deferred function. Log the recovered error for debugging and auditing purposes. Avoid using panic for normal control flow. Document when and why your code might panic, so other developers are aware of the potential for panics and can handle them appropriately.

Interview Tip

Be prepared to explain the difference between error handling with return values and using panic and recover. Know when it's appropriate to use each approach. Understand that recover must be called within a deferred function to be effective. Be prepared to demonstrate an example of how to use panic and recover to handle unexpected errors.

When to Use Them

Use panic when a program reaches a state where it cannot continue execution safely. Use recover to gracefully handle panics and prevent program crashes, especially in long-running services. For example, you may want to use recover in a web server to ensure that a panic in one request does not bring down the entire server.

Alternatives

The primary alternative to using panic and recover is to use explicit error handling with return values. This allows you to handle errors gracefully at the point where they occur, rather than relying on unwinding the call stack. Another alternative is to use error wrapping libraries that provide more context and information about errors. Some libraries also offer structured error handling techniques.

Pros

Panic and recover can provide a centralized way to handle unexpected errors. Recover prevents program crashes and allows execution to continue. They can simplify error handling in some cases, especially when dealing with errors deep within a call stack.

Cons

Overuse of panic and recover can make code harder to understand and debug. It can obscure the control flow of the program. Relying on panic and recover can mask underlying issues and prevent proper error handling. They can also impact performance because unwinding the stack is resource intensive.

FAQ

  • What happens if recover is not called within a deferred function?

    If recover is not called within a deferred function, it will not catch any panics, and the program will crash.
  • Can I recover from multiple panics?

    No, recover only handles the first panic in a given goroutine. Subsequent panics will not be caught by the same recover.
  • Should I use panic for normal error handling?

    No, panic should be reserved for exceptional situations where the program cannot continue safely. Use explicit error handling with return values for normal errors.