liveBook · Manning

Sentinel error

As explained in 100 Go Mistakes and How to Avoid Them

An error sentinel is a predefined error value representing a known condition that callers can compare against.

A sentinel error is a predefined error value representing an expected condition that callers may check. Define it as a package-level variable, conventionally beginning with Err, such as ErrFoo. Use sentinel values for expected outcomes; represent unexpected failures with specific error types. section 7.4

The comparison mistake

Direct comparison works only when the returned value is the sentinel itself: err == sql.ErrNoRows. If another function wraps that error with fmt.Errorf and %w, direct comparison fails even though the underlying condition remains sql.ErrNoRows. Use errors.Is(err, sql.ErrNoRows) when wrapping may occur. section 7.4 section 7.8

Choose the representation according to the meaning of the failure:

  • Return a sentinel error for an expected condition, such as sql.ErrNoRows when a valid query returns no rows. section 7.4
  • Use a specific error type for unexpected failures such as network or connection-polling errors. section 7.4
  • Use errors.Is rather than == when the error may have been wrapped; compare an error type with errors.As. section 7.8
import "errors"
 
var ErrFoo = errors.New("foo")

Inspect the minimal declaration pattern for a sentinel error. section 7.4

err := query()
if err != nil {
    if err == sql.ErrNoRows {     #1
        // ...
    } else {
        // ...
    }
}

Compare a query error directly with sql.ErrNoRows when no wrapping is involved. section 7.4

err := query()
if err != nil {
    if errors.Is(err, sql.ErrNoRows) {
        // ...
    } else {
        // ...
    }
}

Preserve the sentinel check across wrapped errors with errors.Is. section 7.4

How 100 Go Mistakes and How to Avoid Them covers it

How deep it goes
Explains declaration, expected-versus-unexpected classification, direct comparison, and wrapped-error checks.
Examples
Uses ErrFoo, sql.ErrNoRows, io.EOF, query handling, and direct versus wrapped comparisons.
What it assumes
Assumes familiarity with Go errors and functions returning errors; distinguishes expected errors from unexpected failures.
What you can do after
Diagnose/debug with it by distinguishing expected conditions and checking sentinels correctly through wrapped errors.
How it connects
Connects sentinel errors with error wrapping, errors.Is, errors.As, error types, and the error interface.

Also explained in

Compare how 3 books explain sentinel error →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of 100 Go Mistakes and How to Avoid Them. The section links point to the parts of the book it draws on.