Help us shape the future of Go! Take the 2026 Go Developer Survey

xerrors

package
v1.15.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: AGPL-3.0 Imports: 4 Imported by: 13

Documentation

Overview

Package xerrors provides structured application errors with stable typed codes, cause chaining, and key-value context fields.

Every error carries a machine-readable Code (gRPC-aligned wire value), a human-readable message, an optional cause, and optional structured fields. *Err implements errs.CodedError and errs.ContextualError from contracts, enabling logz to enrich log records automatically without importing this package.

Usage:

// Named constructors for common codes
err := xerrors.NotFound("user %s not found", userID)
err := xerrors.InvalidInput("email is required")

// Builder pattern for structured context
err := xerrors.New(xerrors.ErrInvalidInput, "validation failed").
    WithContext("field", "email").
    WithContext("rule", "required").
    WithError(cause)

// Inspecting errors
var e *xerrors.Err
if errors.As(err, &e) {
    switch e.Code() {
    case xerrors.ErrNotFound:
        // handle 404
    }
}

Index

Constants

View Source
const DefaultTypeBase = "urn:einherjar:error:"

DefaultTypeBase prefixes problem type URIs when an application configures none.

A URN rather than an https URL: RFC 9457 allows a non-resolvable type URI and says consumers "SHOULD NOT automatically dereference" it, so nothing has to be hosted for the identifier to be valid. An application that wants to publish documentation configures an https base instead.

Applications are expected to replace this. A client of an application's API couples to the type URI, and it should identify that application's problem types rather than announcing which framework built it.

Variables

This section is empty.

Functions

This section is empty.

Types

type Code

type Code string

Code is the machine-readable error category. Wire values are stable across versions and are identical to gRPC status code names. HTTP mapping is the responsibility of the transport layer, not this package.

const (
	// ErrInvalidInput indicates the request contains malformed or invalid data.
	// HTTP 400 / gRPC INVALID_ARGUMENT.
	ErrInvalidInput Code = "INVALID_ARGUMENT"

	// ErrOutOfRange indicates a parameter or index exceeds the valid bounds.
	// Use when the value itself is well-formed but falls outside accepted limits
	// (e.g. page number past the last page, offset past end of file).
	// HTTP 400 / gRPC OUT_OF_RANGE.
	ErrOutOfRange Code = "OUT_OF_RANGE"

	// ErrUnauthorized indicates the request lacks valid authentication credentials.
	// HTTP 401 / gRPC UNAUTHENTICATED.
	ErrUnauthorized Code = "UNAUTHENTICATED"

	// ErrPermissionDenied indicates the authenticated caller lacks permission for
	// the operation. Authentication is not the issue.
	// HTTP 403 / gRPC PERMISSION_DENIED.
	ErrPermissionDenied Code = "PERMISSION_DENIED"

	// ErrNotFound indicates the requested resource does not exist.
	// HTTP 404 / gRPC NOT_FOUND.
	ErrNotFound Code = "NOT_FOUND"

	// ErrAlreadyExists indicates a resource with the same identifier already exists.
	// Use for creation conflicts (e.g. duplicate email on sign-up).
	// HTTP 409 / gRPC ALREADY_EXISTS.
	ErrAlreadyExists Code = "ALREADY_EXISTS"

	// ErrAborted indicates the operation was aborted due to a concurrent modification
	// or transaction conflict. Unlike ErrAlreadyExists (creation conflict) and
	// ErrPreconditionFailed (business rule), this signals the caller may retry.
	// HTTP 409 / gRPC ABORTED.
	ErrAborted Code = "ABORTED"

	// ErrGone indicates the resource existed but has been permanently removed.
	// Unlike ErrNotFound, this signals the caller should not retry.
	// HTTP 410 / non-standard gRPC extension.
	ErrGone Code = "GONE"

	// ErrPreconditionFailed indicates a required business condition was not met.
	// The input is valid but a rule blocks the action (e.g. "cannot delete an
	// account with active subscriptions").
	// HTTP 412 / gRPC FAILED_PRECONDITION.
	ErrPreconditionFailed Code = "FAILED_PRECONDITION"

	// ErrRateLimited indicates the caller has exceeded a rate limit or quota.
	// HTTP 429 / gRPC RESOURCE_EXHAUSTED.
	ErrRateLimited Code = "RESOURCE_EXHAUSTED"

	// ErrCancelled indicates the operation was cancelled by the caller.
	// HTTP 499 / gRPC CANCELLED.
	ErrCancelled Code = "CANCELLED"

	// ErrInternal indicates an unexpected server-side failure.
	// Use a more specific code when one applies.
	// HTTP 500 / gRPC INTERNAL.
	ErrInternal Code = "INTERNAL"

	// ErrDataLoss indicates unrecoverable data loss or corruption.
	// Reserved for storage-layer integrity failures.
	// HTTP 500 / gRPC DATA_LOSS.
	ErrDataLoss Code = "DATA_LOSS"

	// ErrNotImplemented indicates the requested operation has not been implemented.
	// HTTP 501 / gRPC UNIMPLEMENTED.
	ErrNotImplemented Code = "UNIMPLEMENTED"

	// ErrUnavailable indicates the service is temporarily unable to handle requests.
	// HTTP 503 / gRPC UNAVAILABLE.
	ErrUnavailable Code = "UNAVAILABLE"

	// ErrDeadlineExceeded indicates the operation timed out before completing.
	// HTTP 504 / gRPC DEADLINE_EXCEEDED.
	ErrDeadlineExceeded Code = "DEADLINE_EXCEEDED"
)

func (Code) Description

func (c Code) Description() string

Description returns a human-readable description for the code. Unknown codes return their raw string value.

func (Code) Slug added in v1.14.0

func (c Code) Slug() string

Slug renders the code as a URI path segment: the stable wire value lowercased with underscores turned into hyphens, so INVALID_ARGUMENT becomes invalid-argument. It is the second half of a problem type URI, the first being the application's configured base.

Deriving it means all sixteen codes are covered with no per-code configuration, and a new code gets a type URI for free.

type Err

type Err struct {
	// contains filtered or unexported fields
}

Err is a structured application error carrying a Code, a human-readable message, an optional cause, and optional key-value context fields.

It implements the standard error interface, errors.Unwrap for cause chaining, and json.Marshaler for API responses. It also satisfies errs.CodedError and errs.ContextualError from contracts, enabling logz to enrich log records automatically without importing this package.

Use the builder methods WithContext, WithError, and WithPlatformCode to attach additional information after construction:

err := xerrors.New(xerrors.ErrInvalidInput, "validation failed").
    WithContext("field", "email").
    WithContext("rule", "required").
    WithError(cause)

func Aborted

func Aborted(msg string, args ...any) *Err

Aborted creates an Err with ErrAborted code.

func AlreadyExists

func AlreadyExists(msg string, args ...any) *Err

AlreadyExists creates an Err with ErrAlreadyExists code.

func Cancelled

func Cancelled(msg string, args ...any) *Err

Cancelled creates an Err with ErrCancelled code.

func DataLoss

func DataLoss(msg string, args ...any) *Err

DataLoss creates an Err with ErrDataLoss code.

func DeadlineExceeded

func DeadlineExceeded(msg string, args ...any) *Err

DeadlineExceeded creates an Err with ErrDeadlineExceeded code.

func Gone

func Gone(msg string, args ...any) *Err

Gone creates an Err with ErrGone code.

func Internal

func Internal(msg string, args ...any) *Err

Internal creates an Err with ErrInternal code.

func InvalidInput

func InvalidInput(msg string, args ...any) *Err

InvalidInput creates an Err with ErrInvalidInput code.

func New

func New(code Code, message string) *Err

New creates an Err with the given code and message. No cause is set.

func NotFound

func NotFound(msg string, args ...any) *Err

NotFound creates an Err with ErrNotFound code.

func NotImplemented

func NotImplemented(msg string, args ...any) *Err

NotImplemented creates an Err with ErrNotImplemented code.

func OutOfRange

func OutOfRange(msg string, args ...any) *Err

OutOfRange creates an Err with ErrOutOfRange code.

func PermissionDenied

func PermissionDenied(msg string, args ...any) *Err

PermissionDenied creates an Err with ErrPermissionDenied code.

func PreconditionFailed

func PreconditionFailed(msg string, args ...any) *Err

PreconditionFailed creates an Err with ErrPreconditionFailed code.

func RateLimited

func RateLimited(msg string, args ...any) *Err

RateLimited creates an Err with ErrRateLimited code.

func Unauthorized

func Unauthorized(msg string, args ...any) *Err

Unauthorized creates an Err with ErrUnauthorized code.

func Unavailable

func Unavailable(msg string, args ...any) *Err

Unavailable creates an Err with ErrUnavailable code.

func Wrap

func Wrap(code Code, message string, err error) *Err

Wrap creates an Err that wraps an existing error with a code and message. The wrapped error is accessible via errors.Is, errors.As, and Err.Unwrap.

func (*Err) Code

func (e *Err) Code() Code

Code returns the typed error code.

func (*Err) Detailed

func (e *Err) Detailed() string

Detailed returns a verbose string useful for debugging. Format: "code: X | message: Y | cause: Z | fields: {...}"

func (*Err) Error

func (e *Err) Error() string

Error implements the error interface. Format: "INVALID_ARGUMENT: username is required → original cause"

func (*Err) ErrorCode

func (e *Err) ErrorCode() string

ErrorCode satisfies errs.CodedError. logz calls this to append error_code to log records without importing this package.

func (*Err) ErrorContext

func (e *Err) ErrorContext() map[string]any

ErrorContext satisfies errs.ContextualError. logz calls this to append context fields to log records. The returned map is read-only by logz; use Fields() if you need a safe copy.

func (*Err) Fields

func (e *Err) Fields() map[string]any

Fields returns a shallow copy of the context fields. Returns an empty (non-nil) map if no fields have been set.

func (*Err) Issues added in v1.14.0

func (e *Err) Issues() []Issue

Issues returns the recorded causes, or nil.

func (*Err) MarshalJSON

func (e *Err) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler, emitting the RFC 9457 problem shape with DefaultTypeBase and without the transport-filled members.

It agrees with what the HTTP layer sends apart from Status and Instance, which need a request. Before v1.14.0 it emitted a third shape that nothing in the framework used and that had drifted from the one clients actually received — two implementations of the same body, only one of them reachable. Output: {"code":"NOT_FOUND","platform_code":"...","message":"...","fields":{...}} platform_code and fields are omitted when empty.

func (*Err) Message

func (e *Err) Message() string

Message returns the human-readable error message.

func (*Err) PlatformCode

func (e *Err) PlatformCode() string

PlatformCode returns the platform-level error code, or "" if none was set.

func (*Err) Problem added in v1.14.0

func (e *Err) Problem(typeBase string) Problem

Problem renders the error as an RFC 9457 problem detail, with the type URI built from typeBase and the code's slug. An empty typeBase falls back to DefaultTypeBase.

Status and Instance are left zero: see Problem.

Fields are deliberately not copied in. They are the operator's log context, not the caller's business — the two used to share one map, which meant anything added for debugging was also published. Client-facing causes go in Errors.

func (*Err) Unwrap

func (e *Err) Unwrap() error

Unwrap returns the underlying cause, enabling errors.Is and errors.As to walk the full cause chain.

func (*Err) WithContext

func (e *Err) WithContext(key string, value any) *Err

WithContext adds a key-value pair to the error's context fields and returns the receiver for chaining. Calling it multiple times with the same key overwrites the previous value.

func (*Err) WithError

func (e *Err) WithError(err error) *Err

WithError sets the underlying cause and returns the receiver for chaining.

func (*Err) WithIssue added in v1.14.0

func (e *Err) WithIssue(pointer, detail string) *Err

WithIssue records one cause of the error, to be reported to the caller in the problem's errors array. Repeat it to report several.

pointer is a JSON Pointer into the request body with the "#" prefix RFC 9457 uses — "#/age". Pass an empty pointer when the cause is not a location in the body.

This is the client-facing counterpart to Err.WithContext: an issue is for whoever made the request, a context field is for whoever reads the logs.

func (*Err) WithPlatformCode

func (e *Err) WithPlatformCode(code string) *Err

WithPlatformCode sets a platform-level error code and returns the receiver for chaining. Platform codes are domain-specific identifiers (e.g. "EMPLOYEE_NOT_FOUND") intended for consuming applications — such as a frontend — that need to map errors to localised user-facing messages.

Platform codes are optional. Errors that have no user-actionable meaning (e.g. 500 internal errors) should not carry one.

type Issue added in v1.14.0

type Issue struct {
	Detail  string `json:"detail"`
	Pointer string `json:"pointer,omitempty"`
}

Issue is one entry of a problem's errors array: a single thing wrong with a request, optionally located within it.

It exists because one failed request often has more than one cause. Reporting only the first forces a caller into a fix-resubmit-discover loop, one round trip per mistake, which is the behaviour this type replaces.

Pointer is a JSON Pointer identifying where in the request body the problem is, carrying the "#" prefix that RFC 9457 writes in its own example — "#/age", "#/profile/color". It is empty when the cause is not a location in the body: a rule spanning two fields, or a conflict with state the body cannot express.

type Problem added in v1.14.0

type Problem struct {
	// Type identifies the kind of problem, and is what a client switches on
	// instead of parsing Detail. It is a URI reference, not necessarily a URL.
	Type string `json:"type"`
	// Title summarises the type and does not change between occurrences of it.
	Title string `json:"title"`
	// Status mirrors the HTTP status code. RFC 9457 makes it advisory and requires
	// it to equal the status actually sent. Filled by the transport.
	Status int `json:"status,omitempty"`
	// Detail explains this occurrence, and is the member that varies per request.
	Detail string `json:"detail,omitempty"`
	// Instance identifies this occurrence. Filled by the transport.
	Instance string `json:"instance,omitempty"`

	// Code is the stable gRPC-aligned code, kept so that callers written against
	// it keep working and so the 16-code set stays addressable.
	Code string `json:"code,omitempty"`
	// PlatformCode is the application's own catalogue code, when it sets one.
	PlatformCode string `json:"platform_code,omitempty"`
	// Errors lists every cause, when there is more than one or when a cause can be
	// located in the request body.
	Errors []Issue `json:"errors,omitempty"`
}

Problem is an RFC 9457 problem detail — the standard shape for an HTTP error response, served as "application/problem+json".

Two members are deliberately left for the transport to fill, because they are the only two this package cannot know:

  • Status is the HTTP status code. Mapping a Code to a status belongs to the transport layer, which is Code's long-standing contract.
  • Instance identifies this one occurrence, which in practice is the request ID — and there is no request here.

Everything else comes from the Err. Build one with Err.Problem.

Code, PlatformCode and Errors are extension members. RFC 9457 provides for them ("problem type definitions MAY extend the problem details object") and requires consumers to ignore extensions they do not recognise, which is what makes it safe to add more later.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL