Documentation
¶
Overview ¶
Package xerrors provides structured application errors with stable machine-readable codes, human-readable messages, cause chaining, and key-value context fields.
Each error carries a Code that maps to a well-known category (invalid input, not found, internal, etc.) and is stable across versions — safe to persist, transmit in API responses, or switch on programmatically.
Basic usage ¶
err := xerrors.New(xerrors.ErrNotFound, "user not found")
// With cause chaining
err := xerrors.Wrap(xerrors.ErrInternal, "failed to query database", dbErr)
// Convenience constructors
err := xerrors.NotFound("user %s not found", userID)
// Builder pattern
err := xerrors.New(xerrors.ErrInvalidInput, "validation failed").
WithContext("field", "email").
WithContext("tag", "required")
Cause chaining ¶
Err.Unwrap is implemented, so errors.Is and errors.As walk the full cause chain:
if errors.Is(err, io.ErrUnexpectedEOF) { ... }
var e *xerrors.Err
if errors.As(err, &e) {
log.Println(e.Code())
}
Structured logging (duck-typing bridge) ¶
Err.ErrorCode and Err.ErrorContext satisfy the private interfaces that logz defines internally. Passing an *Err to logger.Error automatically enriches the log record with error_code and context fields — without xerrors importing logz or logz importing xerrors.
Index ¶
- type Code
- type Err
- func (e *Err) Code() Code
- func (e *Err) Detailed() string
- func (e *Err) Error() string
- func (e *Err) ErrorCode() string
- func (e *Err) ErrorContext() map[string]any
- func (e *Err) Fields() map[string]any
- func (e *Err) MarshalJSON() ([]byte, error)
- func (e *Err) Message() string
- func (e *Err) PlatformCode() string
- func (e *Err) Unwrap() error
- func (e *Err) WithContext(key string, value any) *Err
- func (e *Err) WithError(err error) *Err
- func (e *Err) WithPlatformCode(code string) *Err
Constants ¶
This section is empty.
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. // The caller should fix the input before retrying. ErrInvalidInput Code = "INVALID_ARGUMENT" // The caller should authenticate and retry. ErrUnauthorized Code = "UNAUTHENTICATED" // ErrPermissionDenied indicates the authenticated caller lacks permission for the operation. // Authentication is not the issue — the caller is authenticated but not authorised. ErrPermissionDenied Code = "PERMISSION_DENIED" // ErrNotFound indicates the requested resource does not exist. 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). // For state-based conflicts not related to creation, use ErrPreconditionFailed. ErrAlreadyExists Code = "ALREADY_EXISTS" // ErrGone indicates the resource existed but has been permanently removed. // Unlike ErrNotFound, this signals the caller should not retry — the resource // is gone for good (e.g. a soft-deleted record that has been purged). ErrGone Code = "GONE" // ErrPreconditionFailed indicates the operation was rejected because a required // condition was not met. The input is valid but a business rule blocks the action // (e.g. "cannot delete an account with active subscriptions", or an optimistic-lock // mismatch). Different from ErrAlreadyExists (duplicate creation) and // ErrInvalidInput (bad data). ErrPreconditionFailed Code = "FAILED_PRECONDITION" // ErrRateLimited indicates the caller has exceeded a rate limit or exhausted a quota. ErrRateLimited Code = "RESOURCE_EXHAUSTED" // ErrCancelled indicates the operation was cancelled, typically because the caller // disconnected or the request context was cancelled. // Useful for translating context.Canceled to a structured error at service boundaries. ErrCancelled Code = "CANCELLED" // ErrInternal indicates an unexpected server-side failure. // This code should not be used when a more specific code applies. ErrInternal Code = "INTERNAL" // ErrNotImplemented indicates the requested operation has not been implemented. ErrNotImplemented Code = "UNIMPLEMENTED" // The caller may retry with backoff. ErrUnavailable Code = "UNAVAILABLE" // ErrDeadlineExceeded indicates the operation timed out before completing. ErrDeadlineExceeded Code = "DEADLINE_EXCEEDED" )
func (Code) Description ¶
Description returns a human-readable description for the code. Unknown codes return their raw string value.
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 the private duck-typing interfaces that logz uses internally to enrich log records — without either package importing the other.
Use the builder methods Err.WithContext, Err.WithError, and Err.WithPlatformCode to attach additional information after construction:
err := xerrors.New(xerrors.ErrInvalidInput, "validation failed").
WithContext("field", "email").
WithContext("rule", "required").
WithError(cause)
err := xerrors.New(xerrors.ErrNotFound, "employee not found").
WithPlatformCode("EMPLOYEE_NOT_FOUND")
func Internal ¶
Internal creates an Err with ErrInternal code. msg is formatted with args using fmt.Sprintf rules.
func InvalidInput ¶
InvalidInput creates an Err with ErrInvalidInput code. msg is formatted with args using fmt.Sprintf rules.
func NotFound ¶
NotFound creates an Err with ErrNotFound code. msg is formatted with args using fmt.Sprintf rules.
func Wrap ¶
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) Detailed ¶
Detailed returns a verbose string useful for debugging. Format: "code: X | message: Y | cause: Z | fields: {...}"
func (*Err) Error ¶
Error implements the error interface. Format: "INVALID_ARGUMENT: username is required → original cause"
func (*Err) ErrorCode ¶
ErrorCode returns the string value of the error code.
This method satisfies the private errorWithCode interface that logz defines internally. Passing an *Err to logger.Error automatically enriches the log record with an error_code field — without xerrors importing logz.
func (*Err) ErrorContext ¶
ErrorContext returns the raw context fields map.
This method satisfies the private errorWithContext interface that logz defines internally. The returned map is used read-only by logz; callers who need a safe copy should use Err.Fields instead.
func (*Err) Fields ¶
Fields returns a shallow copy of the context fields. Returns an empty (non-nil) map if no fields have been set.
func (*Err) MarshalJSON ¶
MarshalJSON implements json.Marshaler. Output: {"code":"NOT_FOUND","platformCode":"EMPLOYEE_NOT_FOUND","message":"...","fields":{...}} platformCode and fields are omitted when empty.
func (*Err) PlatformCode ¶ added in v0.10.0
PlatformCode returns the platform-level error code, or an empty string if none was set.
func (*Err) Unwrap ¶
Unwrap returns the underlying cause, enabling errors.Is and errors.As to walk the full cause chain.
func (*Err) WithContext ¶
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) WithPlatformCode ¶ added in v0.10.0
WithPlatformCode sets a platform-level error code and returns the receiver for chaining. Platform codes are domain-specific identifiers (e.g. "EMPLOYEE_NOT_FOUND") that operate independently of the transport-level Code. They are intended for consuming applications — such as a frontend — that need to map errors to localised user-facing messages without relying on the generic transport code.
Platform codes are optional. Errors that do not have a user-actionable meaning (e.g. 500 internal errors, infrastructure failures) should not carry one; the consuming application renders a generic fallback in those cases.