-
Release v0.10.0 Stable
released this
2026-03-25 16:43:42 -06:00 | 0 commits to main since this releasev0.10.0
code.nochebuena.dev/go/xerrorsOverview
xerrorsprovides a single structured error type —*Err— that carries a typed machine-readableCode, a human-readable message, an optional cause, and optional key-value context fields. It replaces ad-hoc string errors and sentinel variables with a consistent, JSON-serialisable error model that works uniformly across service boundaries, log pipelines, and HTTP transport layers. Error codes are stable wire values aligned with gRPC canonical status names, so they remain meaningful regardless of the transport protocol in use.What's New in v0.10.0
Platform-level error codes
Adds an optional
PlatformCodeto*Errfor domain-specific error identity, decoupled from the transport-levelCode.Motivation: The transport
Code(e.g.NOT_FOUND,ALREADY_EXISTS) is intentionally generic — it drives HTTP status codes and gRPC status codes at the transport layer. This makes it unsuitable for driving per-case translations in a consuming frontend. ANOT_FOUNDcould mean an employee, a role, or a branch was not found — the frontend cannot distinguish them and falls back to a generic message.PlatformCodesolves this cleanly by operating at the platform/domain layer, independently of transport:// Service layer — set a platform code on any actionable domain error return xerrors.New(xerrors.ErrNotFound, "employee not found"). WithPlatformCode("EMPLOYEE_NOT_FOUND") return xerrors.New(xerrors.ErrAlreadyExists, "email already registered"). WithPlatformCode("EMAIL_ALREADY_EXISTS")The JSON response includes both fields:
{ "code": "NOT_FOUND", "platformCode": "EMPLOYEE_NOT_FOUND", "message": "employee not found" }The consuming application (e.g. a Spanish-first frontend) maps
platformCodeto a translated message.codestill drives the HTTP status. Both are independent.Platform codes are optional. Errors without a user-actionable meaning — 500 internal errors, infrastructure failures, authentication rejections — should not carry one. The frontend renders a generic fallback for those regardless.
New API
(*Err).WithPlatformCode(code string) *Err— chainable builder; attaches a platform code(*Err).PlatformCode() string— getter; returns the platform code or empty string if not setMarshalJSONnow includes"platformCode"when set, omits it otherwise (omitempty)
Backwards compatibility
No existing behaviour changed. All previous constructors, builder methods, and
MarshalJSONoutput for errors without a platform code are identical. This is a purely additive change.What's Included
Code— string type alias for machine-readable error categoriesErrInvalidInput,ErrUnauthorized,ErrPermissionDenied,ErrNotFound,ErrAlreadyExists,ErrGone,ErrPreconditionFailed,ErrRateLimited,ErrCancelled,ErrInternal,ErrNotImplemented,ErrUnavailable,ErrDeadlineExceeded— thirteen typed code constantsCode.Description()— human-readable description for each code*Err— structured error type implementingerror,errors.Unwrap,json.Marshaler,ErrorCode(), andErrorContext()New(code, message)— primary factory constructorWrap(code, message, cause)— factory constructor that wraps an existing error as the causeInvalidInput(msg, args...),NotFound(msg, args...),Internal(msg, args...)— convenience constructors for the three most common codes(*Err).WithContext(key, value)— builder method to attach a key-value field; chainable(*Err).WithError(err)— builder method to set or replace the cause; chainable(*Err).WithPlatformCode(code)— builder method to attach a platform-level code; chainable (new)(*Err).Code()— returns the typedCode(*Err).Message()— returns the human-readable message string(*Err).PlatformCode()— returns the platform code, or empty string (new)(*Err).Fields()— returns a safe shallow copy of all attached context fields(*Err).Detailed()— returns a verbose debug string including code, message, cause, and fields(*Err).ErrorCode()— duck-type bridge satisfying logz's internalerrorWithCodeinterface(*Err).ErrorContext()— duck-type bridge satisfying logz's internalerrorWithContextinterface(*Err).MarshalJSON()— JSON output as{"code":"...","platformCode":"...","message":"...","fields":{...}}
Installation
require code.nochebuena.dev/go/xerrors v0.10.0Design Highlights
CodeandPlatformCodeare intentionally separate concerns:Codeis transport-layer identity (stable, bounded, maps to HTTP/gRPC status);PlatformCodeis domain-layer identity (open-ended, consumer-defined, transport-agnostic).- Error codes are
stringtype aliases with stable wire values matching gRPC canonical status names, making them safe to serialize, store, and compare across service versions. *Errimplementserrors.Unwrap, enabling full stdliberrors.Is/errors.Ascause-chain traversal without any custom helpers.- The logz integration is zero-import:
ErrorCode()andErrorContext()satisfy private duck-typed interfaces inside logz. - HTTP status mapping is deliberately excluded; that responsibility belongs to the transport layer.
Changelog
See CHANGELOG.md.
Downloads