Skip to content
Error Wrapping and errors.Is / errors.As
step 1/7

Reading — step 1 of 7

Learn

~2 min readErrors, Testing, and Performance

Go's error model is values, not exceptions. The errors package (Go 1.13+) gives you tools for wrapping, inspecting, and comparing errors across boundaries. Donovan/Kernighan covers the basics; the wrapping mechanics arrived later and are now idiomatic.

Wrapping: fmt.Errorf with %w

go

The %w verb wraps err inside a new error. Stringification gives you the readable chain:

loading user 42: connection reset by peer

Unlike %s or %v, %w preserves the underlying error so it can be unwrapped later.

Why wrap? Each layer adds context ("loading config", "parsing line 12", etc.) without losing the root cause.

errors.Is — sentinel comparison

For checking against a known sentinel error:

go

errors.Is(err, target) walks the wrapping chain looking for target. Equivalent to err == target plus walking unwraps.

Never use == on errors that might be wrapped — direct comparison fails for wrapped errors.

errors.As — type assertion through the chain

For extracting a specific error TYPE from anywhere in the chain:

go

Like a type assertion that searches through wrapped errors. The second argument MUST be a non-nil pointer to a variable of the target type.

Defining sentinel errors

go

Sentinels are exported so callers can match against them.

Custom error types

For errors that carry structured data:

go

Custom types extract data — sentinels don't carry context.

Custom Unwrap

If you wrap an error in your own struct, implement Unwrap() so errors.Is/As works through it:

go

Now errors.Is(qerr, sql.ErrNoRows) works through your wrapper.

Common mistakes

  • Comparing errors with == — fails on wrapped errors. Use errors.Is.
  • %v instead of %w — looks the same in print, but loses the chain. errors.Is can't peer through.
  • Wrapping the same error twice with the same context — clutters the message. Add context only at meaningful boundaries.
  • Forgetting Unwrap on custom error types — breaks errors.Is/As for callers.
  • Using errors.Is for typed errors — Is is for sentinel comparison. Use errors.As for typed extraction.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…