Table of contents
1.
Introduction
2.
Errors
2.1.
Error Interface
2.2.
Using New Function
2.3.
Using fmt.Errorf()
3.
Error Handling
3.1.
Check For The Error
3.2.
Defer
3.3.
Panic and Recover
4.
FAQs
5.
Key Takeaways
Last Updated: Mar 27, 2024

Go Error Handling

Author ANKIT KUMAR
0 upvote
Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

The concept of errors is available in every programming language. You must have come across a situation where your code does not run, and an error is thrown. Errors indicate a condition where something is wrong in our program.

Errors are defined as unwelcome and unusual conditions that occur in the program. It can be at the compile or run time. Accessing a non-existent file, a failed database connection, or unusual user inputs are a few examples. 

In this article, we will first discuss the error in Go and then the ways to handle the errors that can occur in our program.

Errors

We have already discussed the definition of errors. Errors are unavoidable in any program. An error indicates if something unexpected occurs. Errors also contribute to code stability and maintainability. Without errors, today's programs would be extremely buggy due to a lack of testing.

Error Interface

type error interface {  
    Error() string
}

It only has one method with the signature Error() string. This method returns an error description.

When printing the error, the fmt.Println function internally calls the Error() string method to obtain the error description.

Example:

package main
import "fmt"

func main() {
    
    // trying to divide a number by zero will
    // throw an error
    fmt.Println(5/0)
}

Output: 

./main.go:9:18: division by zero

Before we move on to discuss error handling, let's first discuss some ways to create errors in Go.

Using New Function

The errors package in Go has a function called New(). The New() function can be used to create errors.

Syntax:

errors.New(string message)

Example: 

package main
 
 //import fmt and errors package
import (
    "fmt"
    "errors"
)
 
 //function to determine
 //whether the person is atleast 18 years of age
func isEligibleVoter(age int) (int, error) {
    if age < 18 {
        return -1, errors.New("You are not eligible to vote!") //this is how error is thrown
    } else {
        return 1, nil
    }
}
 
 //main() function which calls the other function 
func main() {
    ok, err := isEligibleVoter(13)
    
    if err != nil {
        fmt.Println(err, ok) 
    } else{
        fmt.Println("You can vote...")
    }
}

Output: 

You are not eligible to vote! -1

Using fmt.Errorf()

In the Go programming language, the fmt.Errorf() function allows us to use the formatting features to create descriptive error messages. The function is available in the fmt package.

Example:

// Including the main package
package main


// Importing fmt
import (
"fmt"
)


// Calling main
func main() {


data :=0.7
percentage :="percent"


// Calling the Errorf() function 
//%f for float type and %s for string
err := fmt.Errorf(" There is %f %s error in the data.", data, percentage)


// Printing the error message
fmt.Println(err)
}

Output: 

There is 0.700000 percent error in the data.

Error Handling

Now that you understand how to create custom errors and extract as much information as possible from errors, let's look at how to handle errors in functions.

Check For The Error

Most errors are not handled directly in functions but are instead returned as a return value. We can use the fact that Golang supports multiple return values for a function. As a result, you can return your error alongside the normal result of the function - errors are always returned as the last argument.

Example: 

package main
 
import (
    "fmt"
    "errors"
)


// function to return an error
func demonstrateErrorHandling( val int) (int, error) {  // declare return type here
    return val, errors.New("There seems to be an error!")  // return it here
}


//main function
func main(){
    getVal, ErrorOccurred := demonstrateErrorHandling(20) // call demonstrateErrorHandling(), it returns an error
    
    // ErrorOccurred value is not nil
    if ErrorOccurred != nil{
        // print the value of ErrorOccurred
        fmt.Println(ErrorOccurred)
    }else{
        fmt.Println("No error has occurred", getVal, ErrorOccurred)
    }
}

Output: 

There seems to be an error!

If the returned error is not nil, it usually indicates that there is a problem and that you must handle the error properly. Depending on the situation, this could mean using a log message to warn the user, retrying the function until it works, or closing the application entirely. The only disadvantage is that Go does not enforce handling returned errors, which means you could simply ignore handling errors entirely.

Defer

Defer statements in Go delay the execution of the function or method or an anonymous method until the nearby functions return. Defer statements are commonly used to ensure that files are closed when their use is no longer required, to close the channel, or to catch panics in the program.

Example: 

// Go program to illustrate the
// concept of the defer statement
package main


import "fmt"


// create three different functions to demonstrate defer
// the first function
func first(){
    fmt.Println("Printing from the first function...")
}


// the second function
func second(){
    fmt.Println("Printing from the second function...")
}


// This is the function which we wish to defer
func third(){
    fmt.Println("This is the critical section. I want to defer this.")
}
func main() {


defer third()
second()
first()
}

Output: 

Printing from the second function...
Printing from the first function...
This is the critical section. I want to defer this.

Explanation:

Although we call the third() function before the second() and first() in the main function, using defer statements will defer the execution of the third() function because of which the statement inside the third() function is printed at the end.

Panic and Recover

Panic is similar to exceptions in programming languages like Java. Panic is used to exit a program when it detects abnormal conditions. We use defer and recover to deal with panic.

Example of panic:

package main
import "fmt"


func main() {
    fmt.Println("Before Panic.")
    panic("panic occurred")
    fmt.Println("After panic")
}

Output: 

Before Panic.
panic: panic occurred

goroutine 1 [running]:
main.main()
/home/main.go:5 +0x96

For recovering from a panic, Go has a built-in function called recover. From the above example, we can see that the print statement after the panic keyword is not executed. The only function that gets executed after the panic is the deferred function. Therefore we must put our recover() function inside the deferred function to ensure that it gets executed.

Example of panic with recover:

package main


import (  
    "fmt"
)


// function to recover f2()
func recoverf2() {  
    if r := recover(); r!= nil {
        fmt.Println("recovered from ", r)
    }
}


// f2() function 
//it defers recoverf2()
// panic keyword is used to create a panic inside f2()
func f2() {  
    defer recoverf2()
    panic("Creating panic inside f2")
    fmt.Println("returned normally from f2")
}


// the main() function
func main() {  
    defer fmt.Println("deferred call in main")
    f2()
    fmt.Println("returned normally from main")
}

Output: 

recovered from  Creating panic inside f2
returned normally from main
deferred call in main

FAQs

1.What are errors in Go?

Errors are defined as unwelcome and unusual conditions that occur in the program. It can be at the compile or run time.

2. What are the two simple ways to create an error in Go?

The two ways are:

i. Using the New() function.

ii. Using fmt.Errorf() function.

3. Why is it important to handle the errors?

If the errors are not handled appropriately, the program will be very buggy resulting in an abrupt halting in execution.

4. What is defer?

Defer statements in Go delay the execution of the function or method or an anonymous method until the nearby functions return.

5. What is panic and recover() in Go?

Panic is used to exit a program when it detects abnormal conditions. The recover() function is a built-in Go function that is used inside a deferred function. It helps in recovering from panic.

Key Takeaways

In this article, we have extensively discussed errors and their handling in Go.

  • Errors are defined as unwelcome and unusual conditions that occur in the program. It can be at the compile or run time.
  • Most errors are not handled directly in functions but are instead returned as a return value.
  • The only function that gets executed after the panic is the deferred function. Therefore we must put our recover() function inside the deferred function to ensure that it gets executed.

We hope that this blog has helped you enhance your knowledge regarding error handling and if you would like to learn more, check out our articles here. Do upvote our blog to help other ninjas grow. Happy Coding!

Live masterclass