Documentation
¶
Overview ¶
Package failure provides typed, HTTP-aware errors with optional code, description and payload metadata, plus helpers for wrapping errors with the name of the function that produced them.
Typed errors ¶
Every typed error is an Error of a Kind (invalid argument, unauthorized, forbidden, not found, timeout, conflict, unprocessable entity, internal server). Build one with the generic New, or with the equivalent New<Kind>Error helper; Is / As report and extract the category anywhere in the chain, and HTTPStatus maps it to a status code:
err := failure.New[failure.NotFound]("user", failure.WithCode(failure.NewErrorCode("USER_404")))
failure.Is[failure.NotFound](err) // true
failure.HTTPStatus(err) // 404
failure.Code(err) // "USER_404"
// The named helpers are thin wrappers over the generic form:
failure.NewNotFoundError("user") // == failure.New[failure.NotFound]("user")
failure.IsNotFoundError(err) // == failure.Is[failure.NotFound](err)
// As returns the concrete typed error for direct inspection:
if e, ok := failure.As[failure.NotFound](err); ok {
_ = e.Code()
}
WithCause attaches an underlying error that stays reachable through errors.Is, errors.As and Cause:
err := failure.NewNotFoundError("user not found", failure.WithCause(sql.ErrNoRows))
errors.Is(err, sql.ErrNoRows) // true
WithStack records the call stack where the error is created — an automatic alternative to threading Breadcrumb names by hand. It is read back with StackTrace, survives wrapping, and never appears in the Error() string:
err := failure.NewNotFoundError("user", failure.WithStack())
frames := failure.StackTrace(err) // []runtime.Frame, caller-first
Metadata and rendering ¶
An error carries up to four pieces of metadata, each with a distinct audience:
- message — the short, primary error text passed to New.
- code — a stable, machine-readable identifier (see ErrorCode) for programmatic handling; inspect it with Code and HasCode.
- description — a human-readable, client-facing message safe to surface to the caller of an API; read it with Description.
- payload — structured key/value context (e.g. the offending field); read it with Payload. It is cloned on the way in and out, so it stays immutable.
Description and Error target different audiences. Description returns only the public, client-facing text. Error returns the full, private rendering — message, code, description, payload and cause concatenated — meant for logs, not for API responses: returning err.Error() to a client can leak the underlying cause and payload. Build client responses from Description (with HTTPStatus and Code), and reserve Error for logging.
Breadcrumbs ¶
Breadcrumb wraps errors with the name of the function that returned them, building a readable call trail without losing the original chain:
const breadcrumb failure.Breadcrumb = "GetUser" return breadcrumb.Wrap(err)
Index ¶
- func Cause(err error) error
- func Causes(err error) []error
- func Description(err error) string
- func HTTPStatus(err error) int
- func HasCode(err error, code ErrorCode) bool
- func Is[K Kind](err error) bool
- func IsConflictError(err error) bool
- func IsForbiddenError(err error) bool
- func IsInternalServerError(err error) bool
- func IsInvalidArgumentError(err error) bool
- func IsNotFoundError(err error) bool
- func IsTimeoutError(err error) bool
- func IsUnauthorizedError(err error) bool
- func IsUnprocessableEntityError(err error) bool
- func New[K Kind](message string, opts ...Option) error
- func NewConflictError(message string, opts ...Option) error
- func NewForbiddenError(message string, opts ...Option) error
- func NewInternalServerError(message string, opts ...Option) error
- func NewInvalidArgumentError(message string, opts ...Option) error
- func NewNotFoundError(message string, opts ...Option) error
- func NewTimeoutError(message string, opts ...Option) error
- func NewUnauthorizedError(message string, opts ...Option) error
- func NewUnprocessableEntityError(message string, opts ...Option) error
- func Payload(err error) map[string]string
- func StackTrace(err error) []runtime.Frame
- type Breadcrumb
- type Conflict
- type ConflictError
- type Error
- type ErrorCode
- type Forbidden
- type ForbiddenError
- type InternalServer
- type InternalServerError
- type InvalidArgument
- type InvalidArgumentError
- type Kind
- type NotFound
- type NotFoundError
- type Option
- type Timeout
- type TimeoutError
- type Unauthorized
- type UnauthorizedError
- type UnprocessableEntity
- type UnprocessableEntityError
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Cause ¶
Cause returns the root error of an error tree. It follows errors.Unwrap for single-wrapped errors and, for multi-error nodes (those implementing Unwrap() []error, such as the result of Breadcrumb.MultiWrap or errors.Join), it descends into the first non-nil branch. It returns nil for a nil error.
func Causes ¶
Causes returns the root cause of every branch of the nearest multi-error node (those implementing Unwrap() []error, such as the result of Breadcrumb.MultiWrap or errors.Join) in err's chain. It descends single-wrapped errors to reach that node, then applies Cause to each non-nil branch — so where Cause keeps only the first branch, Causes keeps them all. For an error without a multi-error node it returns a one-element slice holding Cause(err); for a nil error it returns nil.
func HTTPStatus ¶
HTTPStatus returns the HTTP status of the first typed error in err's chain, or 500 if none is present.
func NewUnprocessableEntityError ¶
Types ¶
type Breadcrumb ¶ added in v0.2.0
type Breadcrumb string
Breadcrumb is the name of a function that can return an error. Wrapping an error with it prepends that name, so a chain of Wrap calls leaves a trail of names leading back to where the failure started — like the breadcrumbs Hansel and Gretel dropped to find their way home (see https://en.wikipedia.org/wiki/Breadcrumb_navigation).
Example:
func ThisFunction(fn func() error) error {
const breadcrumb failure.Breadcrumb = "ThisFunction"
if err := fn(); err != nil {
return breadcrumb.Wrap(err)
}
return nil
}
func (Breadcrumb) MultiWrap ¶ added in v0.2.0
func (b Breadcrumb) MultiWrap(errs ...error) error
MultiWrap joins several errors under one breadcrumb. nil and all-nil inputs collapse to a nil error. Unlike errors.Join the joined message stays on a single line ("; "-separated), so aggregated failures remain readable inside one-line log fields such as a JSON message string. Every branch stays reachable through errors.Is, errors.As and Unwrap() []error, so Cause and Causes can walk them.
func (Breadcrumb) Wrap ¶ added in v0.2.0
func (b Breadcrumb) Wrap(err error) error
Wrap prepends the breadcrumb to err, leaving the original chain reachable through errors.Is, errors.As and Unwrap. A nil error stays nil.
type Conflict ¶
type Conflict struct{}
type Error ¶
type Error[K Kind] struct { // contains filtered or unexported fields }
Error is a typed error of category K carrying an optional code, description, payload and cause. Construct it with New (or a New<Kind>Error helper) and inspect it with Is / As.
func As ¶
As finds the first Error of kind K in err's chain and returns it with true, or the zero Error and false.
func (Error[K]) Error ¶
Error prepends the category prefix to the shared metadata.
func (Error[K]) HTTPStatus ¶
HTTPStatus reports the HTTP status code associated with the error's kind.
func (Error) StackTrace ¶ added in v0.2.0
StackTrace returns the call stack captured if the error was built with WithStack, or nil. The trace starts at the caller that created the error.
type Forbidden ¶
type Forbidden struct{}
type InternalServer ¶
type InternalServer struct{}
type InternalServerError ¶
type InternalServerError = Error[InternalServer]
type InvalidArgument ¶
type InvalidArgument struct{}
type InvalidArgumentError ¶
type InvalidArgumentError = Error[InvalidArgument]
type Kind ¶
type Kind interface {
// contains filtered or unexported methods
}
Kind identifies an error category (its human-readable prefix and HTTP status). Its methods are unexported on purpose: the set of kinds is closed, so external packages cannot define new ones.
type NotFound ¶
type NotFound struct{}
type Option ¶
type Option func(*baseError)
func WithCause ¶
WithCause attaches an underlying cause to the error. The cause is reachable through errors.Is, errors.As and Cause, and is appended to the Error() string. A nil cause is a no-op.
func WithStack ¶ added in v0.2.0
func WithStack() Option
WithStack records the call stack at the point the error is created, so the failure can be traced without threading Breadcrumb names through every call. Read it back with StackTrace; it is omitted from the Error() string. The stack itself is captured by newBaseError once all options are applied.
type Timeout ¶
type Timeout struct{}
type Unauthorized ¶
type Unauthorized struct{}
type UnauthorizedError ¶
type UnauthorizedError = Error[Unauthorized]
type UnprocessableEntity ¶
type UnprocessableEntity struct{}
type UnprocessableEntityError ¶
type UnprocessableEntityError = Error[UnprocessableEntity]
Source Files
¶
- base_error.go
- breadcrumb.go
- cause.go
- doc.go
- error.go
- error_code.go
- failure.go
- kind.go
- option.go
- stack.go