In Golang, wrapping errors means adding more contextual information to the error which has been returned. For example, the additional information could be the type of error, the cause of the error, or the name of the function where the error is raised.
Wrapping is very useful for debugging since you can precisely and quickly locate the source of the problem.
Golang supports wrapping and unwrapping errors as part of the standard library errors
by using the errors.Unwrap()
and fmt.Errorf()
functions with the %w
verb.
Syntax for wrapping an error in Golang
First we need to create a new error using errors.New()
followed by fmt.Errorf()
with the %w
verb to wrap the error.
var criticalError = errors.New("Serious error")
.....
wrap = fmt.Errorf("...%w...",criticalError,...)
The wrapped error can be unwrapped using the errors.Unwrap()
function.
func Unwrap(err error) error
Example 1: How to Wrap An Error
In the below code, we have added a function validations()
which takes a number and runs validations based on some conditions by again calling the check()
function. Whenever an error is encountered, it will wrap the error using fmt.Errorf()
and the %w
verb to show that “run error” has occurred. The new error is then returned.
package main
import (
"errors"
"fmt"
)
var (
errUhOh = errors.New("oh critical error!!")
)
func check(num int) error {
if num == 1 {
return fmt.Errorf("it's odd")
} else if num == 2 {
return errUhOh
}
return nil
}
func validations(num int) error{
err := check(num)
if err != nil {
return fmt.Errorf("run error: %w", err)
}
return nil
}
func main() {
for num := 1; num <= 5; num++ {
fmt.Printf("validating %d... ", num)
err := validations(num)
if err == errUhOh {
fmt.Println("oh no something has happened!")
} else if err != nil {
fmt.Println("some error is present...", err)
} else {
fmt.Println("valid number only...!")
}
}
}
When the above code is run we get the following output:
validating 1... some error is present... run error: it's odd
validating 2... some error is present... run error: oh critical error!!
validating 3... valid number only...!
validating 4... valid number only...!
validating 5... valid number only...!
If we observe the output, the error message with value 1 includes “run error: it’s odd”. This signifies that the error message was wrapped using fmt.Errorf()
in the validations()
function. The value, “it's odd”, is additional context or information added to the error.
However, there is a minor problem with the code; if we look at the output, we can see that while validating input 2, i.e when the loop is run for the second time inside our main function, we receive the standard error message, “run error: oh, critical error!!” instead of a notification saying “oh no, something has happened!”.The check()
function func check(num int) error
is still returning “oh critical error!!” but in case of errUhoh
error, detection is broken.
This happens because the error returned by validations()
is no longer errUhOh
. Instead, it's the wrapped error created by fmt.Errorf()
within the main()function
. In the if
condition, when the err
variable is compared to errUhOh
, it returns false
as err
isn't equal to errUhOh
any more, it is equal to the error that's wrapping errUhOh
.
Now to fix the error checking of errUhOh
, we need to fetch what's inside the wrapper. Therefore, we need to unwrap it using the errors.Unwrap()
function.
Example 2: How to Unwrap An Error
Here we will extend the above example and use errors.Unwrap
function:
package main
import (
"errors"
"fmt"
)
var (
errUhOh = errors.New("oh critical error!!")
)
func check(num int) error {
if num == 1 {
return fmt.Errorf("it's odd")
} else if num == 2 {
return errUhOh
}
return nil
}
func validations(num int) error{
err := check(num)
if err != nil {
return fmt.Errorf("run error: %w", err)
}
return nil
}
func main() {
for num := 1; num <= 5; num++ {
fmt.Printf("validating %d... ", num)
err := validations(num)
if err == errUhOh || errors.Unwrap(err) == errUhOh {
fmt.Println("oh no something has happened!")
} else if err != nil {
fmt.Println("some error is present...", err)
} else {
fmt.Println("valid number only...!")
}
}
}
Output:
validating 1... some error is present: run error: it's odd
validating 2... oh no something has happened!
validating 3... valid number only...!
Now you know how to encapsulate an error using the %w
verb within fmt.Errorf()
and check the contents of the wrapped error by unwrapping it with the help of the errors.Unwrap()
function.
Track, Analyze and Manage Errors With Rollbar
Managing errors and exceptions in your code is challenging. It can make deploying production code an unnerving experience. Being able to track, analyze, and manage errors in real-time can help you proceed with more confidence. Rollbar automates error monitoring and triaging, making fixing Golang errors easier than ever. Try it today!