Problem: You want to check for specific errors or specific types of errors.
Solution: Use the errors.Is and errors.As functions. The errors.Is function compares an error to a value and the errors.As function checks if an error is of a specific type.
Using errors.Is
The errors.Is function is essentially an equality check. Let’s say you define a set of customized errors in your codebase — for example, ApiErr — which happens when a connection to an API encounters an error:
var ApiErr error = errors.New("Error trying to get data from API")
Elsewhere in your code, you have a function that returns this error:
func connectAPI() error { // some other stuff happening here return ApiErr }
You can use errors.Is to check if the error returned is ApiErr :
if err != nil { if errors.Is(err, ApiErr) { // handle the API error } }
You can also verify if ApiErr is somewhere along the chain of wrapped errors. Take the example of a connect function that returns a ConnectionError that wraps around ApiErr :
func connect() error { return &ConnectionError{ Host: "localhost", Port: 8080, Err: ApiErr, } }
This code still works because ConnectionError wraps around ApiErr :
err := connect() if err != nil { if errors.Is(err, ApiErr) { // handle the API error } }
Using errors.As
The errors.As function allows you to check for a specific type of error. Continue with the same example, but this time around, you want to check if the error is of the type ConnectionError :
err := connect() if err != nil { var connErr *ConnectionError if errors.As(err, &connErr) { log.Errorf("Cannot connect to host %s at port %d", connErr.Host, connErr.Port) } }