In Go, errors are values implementing the error interface: a single method Error() string.
import "errors"
import "fmt"
var ErrNotFound = errors.New("not found")
func parse(s string) error {
return fmt.Errorf("parse %q: %w", s, ErrInvalid)
}
%wUse fmt.Errorf("...: %w", err) so callers can unwrap with errors.Is and errors.As.
if errors.Is(err, ErrNotFound) {
// handle
}
var p *os.PathError
if errors.As(err, &p) {
// path-specific
}
Package-level var ErrXxx = errors.New(...) values are compared with errors.Is, not == on a wrapped chain (unless you know it is the exact value).
type ValidationError struct {
Field string
Msg string
}
func (e *ValidationError) Error() string {
return e.Field + ": " + e.Msg
}
Use errors.As to recover the concrete type.
Libraries should return errors. panic is for programming bugs or unrecoverable situations; recover is rare and usually only at package boundaries (e.g. HTTP handlers middleware).
_ when truly intentional.fmt.Errorf("load user: %w", err).