Skip to content

Instantly share code, notes, and snippets.



Last active Apr 22, 2021
What would you like to do?
Errors in Go

This is my notes from a few articles:

Some error values are mostly just used for control flow. For example, "Access Denied", or "Authentication Required".

In my opinion, you should only add stack trace to an error which is potentially going to break your program. A logical error like we have seen in the authorization example does not need a track state. But since Wrap method can be used to ammend original error message which is also called as annotating an error, the choice is up to you.

The types of errors that would bubble up to be a 500 Internal Server Error generally require investigation by a developer. In these cases, a stacktrace (and ideally other contextual information) is incredibly valuable.

There are a few popular contenders for contemporary error handling in Go.

  • Go 1.13 errors /
  • cockroachdb/errors

Problems with Go 1.13 errors compared to

  1. Replace Wrap with format parameter : %w . Looks simplify the code, but this approach loses compile-time checking. If : %w is not the tail of format string(e.g., "foo : %w bar"), or colon is missing (e.g., "foo %w"), or the space between colon and percent sign is missing (e.g., "foo:%w"), the wrapping will fail without any warning
  2. What’s more serious is that you have to check the condition err != nil before calling xerrors.Errorf. This actually does not simplify the work of the developer at all
  3. Unlike, Go 1.13 errors dropped support for call stack output. And according to the official statement, there is no schedule for this. So is much better choice at the moment.

Problems with cockroachdb/errors:

  1. It is a heavy swiss army knife that doesn't load in the Goland Playground so my co-workers will never let adopt it. 😅
  2. It might not be future compatible with some possible future Go standard lib error stacktrace capture mechanism.

It has very lovely output though. 😏 quirks

If we use %v as format parameter, we’ll get an one-line output string, contains all contextual text in the order of call stack. If change the format parameter to %+v, we’ll get the complete call stack.

If you want to simply wrap error with attach call stack, no additional contextual text is needed, then use WithStack

func foo() error {
   return errors.WithStack(sql.ErrNoRows)

Note: When use Wrap, WithMessage or WithStack, if the err parameter is nil, then nil will be returned, which means that we don’t need to check err != nil condition before calling the method. This keeps the code simple.

Feature comparison (abridged from

Feature Go's <1.13 errors Go 1.13 errors/xerrors cockroachdb/errors
error constructors (New, Errorf etc)
error causes (Cause / Unwrap)
cause barriers (Opaque / Handled)
errors.As(), errors.Is()
automatic error wrap when format ends with : %w
standard wrappers with efficient stack trace capture
transparent protobuf encode/decode with forward compatibility
errors.Is() recognizes errors across the network
comprehensive support for PII-free reportable strings
support for both Cause() and Unwrap() go#31778
errors.FormatError(), Formatter, Printer (under construction)

Further reading

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment