Error Handling in Golang with Panic, Defer, and “Recover”

Everything you need to know about error handling

Mayank Gupta
Oct 31 · 6 min read

This piece is focussed on Error Handling in Golang. We will be talking about simple ways to create and capture custom and runtime Errors in Golang. Golang provides a simple approach to this.

Golang provides a simple interface for error. Each returned error in Golang adheres to this interface definition:

type error interface {
Error() string
}

Creating a Golang Custom Error

We can create a simple custom error in Golang with the following syntax:

package main

import (
"errors"
"fmt"
)

func calculateArea(radius int) (int, error) {
if radius < 0 {
return nil, errors.New("Provide Positive Number")
}
return radius * radius, nil
}

In the above code, we have the following scenario, in order to calculate the area of circle, we need to ensure that the radius passed as a parameter is positive. If the value passed is negative, we will return the area value as “0” along with the custom error object from the function. If the radius value passed is negative, we generate a custom error message using the keyword errors.New. This function creates an object of “error” type and contains a custom error message. Let's call this function with a negative value of “radius”, so that the error is returned from the function call:

package main

import (
"errors"
"fmt"
)

func calculateArea(radius int) (int, error) {
if radius < 0 {
return 0, errors.New("Provide Positive Number")
}
return radius * radius, nil
}

func main() {
areaValue, err := calculateArea(-1);
if err != nil {
fmt.Println("Error Encountered...")
return
}

fmt.Println(areaValue)
}

From the calling function main, thecalculateArea function is called with a negative parameter value. Since the value passed is negative, we expect an “error” object from the function. On function execution, it returns two values. The first value represents the calculated area value and the second parameter represents the “error” object. In the code above, we look for whether the function returns an “error” object or not, if the “error” object returned is “nil”, the function executes further, otherwise, we return the function after displaying the error message.

Try running this code in the custom editor:

While creating custom functions, we should ensure that they’re created so that they send the error status, along with the value to be returned from the function. The code above represents a scenario in which we handle the custom errors. There may be many scenarios where the function throws an unexpected error. We need to look into the details of how to handle these failures too. Let's dig deep into those methods.

“Defer ”, “Panic” and “Recover” keywords…

Working with Defer Keyword

Let's look at this with the help of an example:

package main

import "fmt"

func returnMessage() {
fmt.Println("This is Simple Defer Function Execution")
}

func main() {
defer returnMessage()
fmt.Println("This is line One")
fmt.Println("This is line Two")
fmt.Println("This is line Three")
}

This code adds the defer keyword in front of the returnMessage function call in the main thread. Once the main thread executes, it schedules the call to this returnMessage call, just before returning from the function call. The output is shown below.

Even when the function call is made on the top for returnMessage, it’s still executed at the end of the function, when the function is about to return. This is how the defer keyword works in Golang. Try the above code with the following online editor:

Working with Panic Keyword

The panic keyword is used to terminate the program with a custom error message. When the panic keyword is encountered, the following set of instructions are followed:

  1. Execution for the current function stops
  2. Any function called with defer keyword is executed
  3. The program execution is terminated

Let's start with a simple panic function:

https://gist.github.com/Mayankgupta688/d9e76583191f769c817a5e87a2952524

In the above code, we are calling the panic function in the executePanic function. As soon as the function is executed, the program is terminated. See the output below for this execution:

The program exited on line six when the panic function was executed. The panic function is another way to notify the program of an error and instruct it to terminate with a custom error message. Try the above code in the online editor below:


Adding the “Defer” Keyword to “Panic”

As mentioned, whenever a panic function is introduced, it executes all the defer functions associated with the currently executing thread. The defer function can be used to free up the resources. defer functions are executed just before the termination of the currently executing function. Let's look at an example:

https://gist.github.com/Mayankgupta688/55614af24e9facba7c056651dbd3d4cc

In the above code, we’ve added a defer keyword before the function, where the panic function is called. Let's take a look at the output below:

At line 12, the panic keyword is encountered and immediately the function marked with defer is executed. In the above execution, we can see that the defer function is executed before the function is terminated. As soon as panic is introduced, it searches for all thedefer keywords inside the function and executes them before termination.

Try the code above in the online editor:


Working with Recovery

Once the “panic” situation is encountered, the program terminates. In the real world, the application terminating on error is not good. We need a mechanism to recover from the error. We need a recovery code to avoid unwanted termination of the program.

The defer function is always executed when the function returns — the executed function may or may not have encountered the “panic” situation. We can specify the recovery scenario, inside the “defer” function.

Detecting a “panic” situation

Inside the defer function, we need to check if the function execution encountered the panic situation. In order to detect thìs, we execute the recover function. Once we execute the recover function in the defer function, we receive an error message value that is the same as the parameter value passed to the panic function. The string passed to the panic function is returned as output from the recover function. This does not allow the executing program to terminate — rather it regains control of the executing program. The control is then handled to the caller function, and the caller function executes further normally. Take a look at the example below:

package main

import "fmt"

func recoveryFunction() {
fmt.Println("This is recovery function...")
}

func executePanic() {
defer recoveryFunction()
panic("This is Panic Situation")
fmt.Println("The function executes Completely")
}

func main() {
executePanic()
fmt.Println("Main block is executed completely...")
}

In the above code, inside the defer function, we are invoking the recover function which returns the panic message that was passed to the panic function argument. Since we are using the recover function, the function will not terminate immediately. Instead, the function control will be returned to the caller function mainand resume normal execution, hence recovering from the panic situation.

Let's look for the output from this:

We can see that the function does not terminate. Instead, it returns the execution to the “main” calling function and the next execution progresses normally.

Try the above execution in the online editor below:


Better Programming

Advice for programmers.

Mayank Gupta

Written by

9 Years of Experience with Front-end Technologies and MEAN Stack. Working on all Major UI Frameworks like React, Angular and Vue.

Better Programming

Advice for programmers.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade