Go Standard Error Patterns

Browse canonical Go errors from the standard library with package and sentinel values.

A searchable reference for Go standard-library sentinel errors (io.EOF, sql.ErrNoRows, context.Canceled), concrete error types, and the errors.Is / errors.As / %w wrapping conventions. Runs in your browser.

Why compare with errors.Is instead of == in Go?

Wrapping an error with fmt.Errorf and the %w verb nests the original inside a chain, so a direct == comparison against a sentinel like io.EOF or sql.ErrNoRows fails. errors.Is walks the whole chain and returns true if any wrapped error equals the target.

This is a searchable reference for Go’s standard error patterns — the canonical sentinel errors exported by the standard library (io.EOF, sql.ErrNoRows, context.Canceled), the concrete error types you inspect with errors.As (*os.PathError, *net.DNSError, *json.SyntaxError), and the errors/fmt helpers that tie them together.

How it works

Go errors are just values implementing the error interface, and the standard library distinguishes three families. Sentinel errors are exported package variables (io.EOF, fs.ErrNotExist, context.DeadlineExceeded) that you test against with errors.Is. Error types are concrete structs (*os.PathError, *strconv.NumError) carrying extra fields you extract with errors.As. Helperserrors.New, fmt.Errorf with %w, errors.Is, errors.As, errors.Join — create and unwrap these.

The critical rule is that wrapping with fmt.Errorf("read config: %w", err) nests the original error in a chain. A bare err == io.EOF will then fail, while errors.Is(err, io.EOF) walks the chain and still matches. The same applies to types: errors.As(err, &pathErr) finds a *os.PathError no matter how deeply it is wrapped.

Example

Wrap once, then inspect through the chain:

data, err := io.ReadAll(r)
if err != nil {
    err = fmt.Errorf("read body: %w", err)   // wrap, keep the cause
}

if errors.Is(err, io.ErrUnexpectedEOF) {     // sentinel via chain
    // truncated input
}

var pathErr *os.PathError
if errors.As(err, &pathErr) {                // concrete type via chain
    log.Printf("op=%s path=%s", pathErr.Op, pathErr.Path)
}

Note that sql.ErrNoRows from QueryRow().Scan is a normal result meaning “not found”, not a failure — handle it explicitly with errors.Is rather than treating every non-nil error the same way. Everything runs in your browser; nothing is uploaded.