liveBook · Manning

Errors.Is

As explained in Learn Go with Pocket-Sized Projects

errors.Is is a Go standard-library function that reports whether an error matches a target error through direct or wrapped identity.

A function may return an error with useful context wrapped around a recognizable error. Comparing only the returned error with a sentinel can miss that sentinel. Use errors.Is(err, target) to ask whether the target matches anywhere in err’s error chain. section 5.1.3

Check a validation error

A word-game validator returns fmt.Errorf("expected %d, got %d, %w", expected, actual, errInvalidWordLength) when a guess has the wrong length. A table-driven test checks errors.Is(err, tc.expected): the valid-guess case expects nil, while the too-long case expects errInvalidWordLength. The test recognizes the sentinel without depending on the added length details. section 5.1.3

Listing 5.16 game_internal_test.go: Testing the validateGuess method
package gordle

import (
    "errors"
    "testing"
)

func TestGameValidateGuess(t *testing.T) {
    tt := map[string]struct { #1
        word     []rune
        expected error
    }{
        "nominal": { #2
            word:     []rune("GUESS"),
            expected: nil,
        },
        "too long": {
            word:     []rune("POCKET"),
            expected: errInvalidWordLength,
        }
    }

    for name, tc := range tt {
        t.Run(name, func(t *testing.T) {
            g := New(nil) #3

            err := g.validateGuess(tc.word) #4
            if !errors.Is(err, tc.expected) { #5
                t.Errorf("%c, expected %q, got %q", 
                    tc.word, tc.expected, err) #6
            }
        })
    }
}

The test places expected errors beside inputs and uses errors.Is for both the nil success case and a wrapped validation error. section 5.1.3

Keep the error a caller needs to recognize in the returned chain:

  • Wrap a package sentinel with %w when adding context. ParseDecimal does this for ErrInvalidDecimal when integer parsing fails; its tests also check errors such as ErrTooLarge. section 6.2.4
  • At an HTTP boundary, expose a package-specific sentinel rather than requiring callers to recognize net/http errors. Callers can then check its meaning with errors.Is. section 6.5.3

Use errors.As when the decision requires extracting a particular error type. For example, a gRPC endpoint uses errors.As to recognize InvalidInputError and return InvalidArgument; other errors become Internal. errors.Is is the simpler check when the question is whether a target error matches. section 10.3.2

How Learn Go with Pocket-Sized Projects covers it

How deep it goes
Defines chain matching and demonstrates wrapped-error assertions, without detailing a custom matching implementation.
Examples
Uses a word-length validation test, decimal parsing errors, and caller-facing HTTP errors.
What it assumes
Assumes familiarity with Go error returns and table-driven tests; explains wrapped-error matching directly.
What you can do after
Apply it via Go’s errors package to test wrapped sentinels and recognize package-level errors.
How it connects
Connects error wrapping, sentinel errors, table-driven tests, and errors.As.

Also explained in

Compare how 3 books explain errors.Is →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Go with Pocket-Sized Projects. The section links point to the parts of the book it draws on.