Skip to content
Lesson 2 of 9

Step 1 of 4 · Reading · ~3 min

Learn

Interfaces and Errors

Errors: Sentinels, Wrapping, Custom Types

In Go Fundamentals an error was a value you compared with nil and printed. Here you will match a failure by identity, add context without losing the cause, and pull fields out of an error, including the standard library's.

Sentinels and errors.Is

A sentinel error is a package-level error value that callers compare against. A shelf lookup that fails two ways:

go

order adds context with %w, which formats like %v but also records the wrapped error, forming a chain of errors, each wrapping the next. Now compare three ways to ask "was it a missing item?":

go

== compares the outer wrapper, a different value, and comparing err.Error() text breaks when someone rewords a message. errors.Is(err, target) walks the chain and reports whether any link equals target.

The %v trap

%v and %w print identical text, but only %w keeps the chain:

go

Use %w whenever you wrap an error you received, and only one per Errorf: the grader's Go 1.13 does not support a second.

Custom types and errors.As

StockError carries fields a caller can act on. After wrapping, err.(StockError) fails, because the outer value is the wrapper:

go

errors.As(err, &target) walks the chain for a link whose type matches target's and copies it in; it takes &target because it writes into your variable. The type must match exactly: the chain holds a StockError value, so declare var se StockError.

Library errors are types too

The standard library returns typed errors, and value versus pointer decides what you declare. strconv.Atoi fails with a pointer, *strconv.NumError, whose fields are Func, Num (the text it could not parse) and Err (the reason):

go

The target variable is itself a pointer, so you pass its address, a pointer to a pointer. Declaring var ne strconv.NumError compiles, finds nothing and returns false. Wrap it as before, fmt.Errorf("weight %q: %w", w, err), and the *NumError stays reachable.

When one function can return several kinds, test sentinels with errors.Is, then each type with errors.As, then fall back. Either return an error or deal with it, never both, or every layer prints it again.

Common mistakes

  • Comparing a wrapped error with ==. err == ErrEmpty is false once any layer has wrapped it, so a blank line reaches your fallback and prints line 2: empty line.
  • Wrapping with %v. The text is unchanged, but errors.As finds no *strconv.NumError, so a parse failure reaches the fallback.
  • Returning &RangeError{...} and asserting on a value. The chain holds a pointer, var re RangeError matches nothing, and the failure reaches the fallback.
  • Off-by-one bounds. age > 120 is right; >= rejects a legal 120. Scores at 0 and 100 are legal too.

Your exercise

Each input line is name age score. You complete check, which returns the first problem as a sentinel, a wrapped parse failure or a RangeError, and classify, which turns any of them into one output line. The starter adds the line number with %w, so == can never match; the likeliest mistake is reaching for it.

Up nextGoroutinesGoroutines and Channels

Discussion

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

Sign in to post a comment or reply.

Loading…