How to compare Go errors

Declaring an error, and comparing it with '==' (as in err == myPkg.ErrTokenExpired) is no longer the best practice with Go 1.13 (Q3 2019)

The release notes mentions:

Go 1.13 contains support for error wrapping, as first proposed in the Error Values proposal and discussed on the associated issue.

An error e can wrap another error w by providing an Unwrap method that returns w.
Both e and w are available to programs, allowing e to provide additional context to w or to reinterpret it while still allowing programs to make decisions based on w.

To support wrapping, fmt.Errorf now has a %w verb for creating wrapped errors, and three new functions in the errors package ( errors.Unwrap, errors.Is and errors.As) simplify unwrapping and inspecting wrapped errors.

So the Error Value FAQ explains:

You need to be prepared that errors you get may be wrapped.

If you currently compare errors using ==, use errors.Is instead.
Example:

if err == io.ErrUnexpectedEOF

becomes

if errors.Is(err, io.ErrUnexpectedEOF)
  • Checks of the form if err != nil need not be changed.
  • Comparisons to io.EOF need not be changed, because io.EOF should never be wrapped.

If you check for an error type using a type assertion or type switch, use errors.As instead. Example:

if e, ok := err.(*os.PathError); ok

becomes

var e *os.PathError
if errors.As(err, &e)

Also use this pattern to check whether an error implements an interface. (This is one of those rare cases when a pointer to an interface is appropriate.)

Rewrite a type switch as a sequence of if-elses.


This answer is for Go 1.12 and earlier releases.

Define an error value in a library

package fruits

var NoMorePumpkins = errors.New("No more pumpkins")

Do not create errors with errors.New anywhere in the code but return the predefined value whenever error occurs and then you can do the following:

package shop

if err == fruits.NoMorePumpkins {
     ...
}

See io package errors for reference.

This can be improved by adding methods to hide the check implementation and make the client code more immune to changes in fruits package.

package fruits

func IsNoMorePumpkins(err error) bool {
    return err == NoMorePumpkins
} 

See os package errors for reference.


Try

err.Error() == "Token is expired"

Or create your own error by implementing the error interface.

Tags:

Go