# Simple Guide to Panic Handling and Recovery in Golang

Golang is now one of the most popular languages for development in the industry. More and more organisations are migrating to use Golang because of its ease of use, concurrency patterns and awesome online community.

Go is extremely simple, and has very limited keywords. It is extremely opinionated, and has readily available patterns to achieve certain tasks. One of them is handling panic and recovering from it gracefully. *Let us take a look at it.*

First, let us set up our premise. We are writing a function `printAllOperations`

which will take two integer inputs, and perform sum, subtraction, multiplication and division on them and print out the results.

`func printAllOperations(x int, y int) {`

sum, subtract, multiply, divide := x+y, x-y, x*y, x/y

fmt.Printf("sum=%v, subtract=%v, multiply=%v, divide=%v \n", sum, subtract, multiply, divide)

}

The `main`

method will be calling this function, and letting us know that it was able to complete all the operations successfully.

`func main() {`

x := 20

y := 10

printAllOperations(x, y)

fmt.Println("Exiting main without any issues")

}

On running this code, we will see the following output as expected.

`sum=30, subtract=10, multiply=200, divide=2 `

Exiting main without any issues

But there is an issue here. Let us say we run method with `y:=0`

. In that case, the `printAllOperations`

function will panic because of an illegal `divide by zero`

operation. The output then looks like this:

panic: runtime error: integer divide by zerogoroutine 1 [running]:

main.printAllOperations(0x14, 0x0)

panic.go:22 +0x1b5

main.main()

panic.go:8 +0x37

This is not very helpful. We want to be able to handle this panic in a proper way so the application can exit gracefully while providing useful information to the end user, and possibly even providing partial output to the user.

To do this, we must first understand the `defer`

statement:

A **defer statement** pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns.

This means that when we defer a function, we are **guaranteeing** it’s execution at the end of its surrounding function.

We will make use of this fact for handling panic. When a function panics, it’s execution is stopped, any deferred functions are executed and then the function returns to its caller. To the caller, this function now simply behaves like a call to `panic`

. This process continues upwards to the call stack till all functions in the current goroutine return or panic, and then the program crashes.

`Recover`

is a function provided by Go which takes control of a panicking goroutine. `recover()`

can only be used inside deferred functions. If you call `recover()`

during normal flow, it will simply return `nil`

. However, if a goroutine is panicking, `recover()`

will capture the panic value.

Let us add a defer function to capture the panic value in `printAllOperations`

.

`func printAllOperations(x int, y int) {`

defer func() {

if r := recover(); r != nil {

fmt.Printf("Recovering from panic in printAllOperations error is: %v \n", r)

}

}()

sum, subtract, multiply, divide := x+y, x-y, x*y, x/y

fmt.Printf("sum=%v, subtract=%v, multiply=%v, divide=%v \n", sum, subtract, multiply, divide)

}

As you can see, we have deferred an anonymous function which has a call to `recover()`

. When the code panics, this deferred function will take control of the goroutine and finish the execution.

Now, let us run the main function with `x:=20`

and `y:=0`

. The output is :

`Recovering from panic in printAllOperations error is: runtime error: integer divide by zero `

Exiting main without any issues

As you can see, the control was taken over by the deferred function, which upon detecting a non-nil `panic`

value from `recover()`

, takes control of the flow and return without any error to the main function. The main function then does not need to `panic`

, and finishes with normal flow of execution.

# Data Recovery and Alternative Flows

The above method is quite useful in logging panic data and providing graceful exit, which can be very useful in debugging and fixing issues in the application. But we can also use panic recovery to provide alternative logic flows when one flow panics.

For instance, in our current scenario, since we that only a division operation can cause panic in our code, we may choose to provide an alternate path of execution that will inform the user of the invalid input, and proceed to perform the remaining three operations: addition, subtraction and, multiplication.

To achieve this, first let us add another function that will skip division and perform the rest of the operations.

`func printOperationsSkipDivide(x int, y int) {`

sum, subtract, multiply := x+y, x-y, x*y

fmt.Printf("sum=%v, subtract=%v, multiply=%v \n", sum, subtract, multiply)

}

Now, let us change our defer function to pass flow of control to this function after providing appropriate error message.

`defer func() {`

if r := recover(); r != nil {

fmt.Printf("Recovering from panic in printAllOperations error is: %v \n", r)

fmt.Println("Proceeding to alternative flow skipping division.")

printOperationsSkipDivide(x, y)

}

}()

If we now execute the code with `x:=20`

and `y:=0`

, we will get the following output:

`Recovering from panic in printAllOperations error is: runtime error: integer divide by zero `

Proceeding to alternative flow skipping division.

sum=20, subtract=20, multiply=0

Exiting main without any issues

As you can see, using this pattern we can change the flow of control to alternative paths upon detecting panic in the normal path.

Below is the entire code for this example:

*I hope this guide helps you write better Golang. Feel free to reach out to me in the comments for any questions or suggestions!*