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.

Leave a Comment