← Go, End to End

Go, End to End

Error Handling the Go Way

Go has no exceptions for ordinary error handling. error is just an interface with one method, Error() string, and functions that can fail return one as their last value. The calling code is expected to check it immediately, which is where the famous if err != nil pattern comes from.

go · live, editable, runnable

Go's designers made this choice on purpose. Exceptions create invisible control-flow paths, any line can potentially throw, and the type signature gives you no warning. A returned error makes failure part of the function's visible contract, at the cost of more explicit checking code. Reasonable people disagree about the tradeoff, but it's a deliberate design decision, not an oversight.

Wrapping errors with fmt.Errorf and %w

When an error crosses an abstraction boundary, it's common to wrap it with more context while preserving the original error so callers further up can still inspect it. %w (as opposed to %v or %s) is the verb that does this, it creates a wrapped error that errors.Unwrap (and the functions built on it) can see through.

go · live, editable, runnable

errors.Is and errors.As

errors.Is(err, target) checks whether err, or anything it wraps, matches a specific sentinel error value. errors.As(err, &target) checks whether err, or anything it wraps, can be assigned to a specific error type, and if so assigns it, letting you get at fields on a custom error type buried inside a wrap chain.

go · live, editable, runnable

Sentinel errors vs custom error types

A sentinel error (var ErrNotFound = errors.New(...)) is a single shared value you compare against with errors.Is. A custom error type (a struct implementing the error interface) carries structured data and is checked with errors.As. Use sentinels for simple "this specific known condition happened" signals, and custom types when the caller needs more than a message, like which field failed validation.

Try it yourself: modify the ValidationError example so the error also carries the invalid value, not just the field name, and print both when you extract it with errors.As.