The error interface, wrapping with %w, errors.Is / errors.As.
Wrapping, Is, and As
Errors often need context as they bubble up — "the file couldn't be opened, because the disk is full, because the quota was exceeded". Go 1.13 introduced error wrapping to handle this without losing the original error.
Wrapping with %w
fmt.Errorf has a special verb %w (only one allowed per call) that wraps
another error inside the new one:
data, err := os.ReadFile(path)
if err != nil {
return fmt.Errorf("load config: %w", err)
}
The returned error has a longer message and still contains the original.
errors.Is — compare error values
When you want to ask "is this error (or any error it wraps) equal to a sentinel?"
use errors.Is. It unwraps the chain.
fs.ErrNotExist is a sentinel — a known package-level error value. Define
your own with var ErrNoBudget = errors.New("no budget") and callers can
errors.Is(err, ErrNoBudget) no matter how deeply you wrap it.
errors.As — pull a typed error out
If your error is a struct (like ValidationError from the last lesson), you
want the struct, not just its message. errors.As walks the wrap chain and tries
to assign into the target you give it:
The new mantras
errors.New(...)/fmt.Errorf(...)— make errors.fmt.Errorf("...: %w", err)— wrap an error with context.errors.Is(err, target)— equal to (or wraps) a sentinel?errors.As(err, &t)— extract a typed error.
You'll use these every day.