-
Release v0.9.0 Stable
released this
2026-03-18 13:12:17 -06:00 | 0 commits to main since this releasev0.9.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 Included
Code— string type alias for machine-readable error categoriesErrInvalidInput,ErrUnauthorized,ErrPermissionDenied,ErrNotFound,ErrAlreadyExists,ErrGone,ErrPreconditionFailed,ErrRateLimited,ErrCancelled,ErrInternal,ErrNotImplemented,ErrUnavailable,ErrDeadlineExceeded— twelve 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).Code()— returns the typedCode(*Err).Message()— returns the human-readable message string(*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":"...","message":"...","fields":{...}}
Installation
require code.nochebuena.dev/go/xerrors v0.9.0Design Highlights
- 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 (seedocs/adr/ADR-001-typed-error-codes.md). *Errimplementserrors.Unwrap, enabling full stdliberrors.Is/errors.Ascause-chain traversal without any custom helpers (seedocs/adr/ADR-002-stdlib-errors-compatibility.md).- The logz integration is zero-import:
ErrorCode()andErrorContext()satisfy private duck-typed interfaces inside logz, so passing an*Errtologger.Errorautomatically enriches the log record witherror_codeand context fields — withoutxerrorsimportinglogz. - HTTP status mapping is deliberately excluded; that responsibility belongs to the transport layer, keeping this package dependency-free and protocol-agnostic.
Known Limitations & Edge Cases
errors.Ason a cause chain stops at the first*Errit encounters — if multiple*Errvalues are nested, only the outermost one's fields are surfaced in a singleAscall.ErrorContext()returns the live internal fields map. Callers who receive an*Errand mutate the map returned byErrorContext()will corrupt the error's state. UseFields()for a safe copy.- Convenience constructors (
InvalidInput,NotFound,Internal) cover only three of the twelve codes. Other codes requireNeworWrapdirectly. - There is no HTTP status code mapping in this package. Applications must maintain their own
Code→ HTTP status table at the transport layer. WithContextsilently overwrites a field if the same key is set twice; no warning or error is produced.
v0.9.0 → v1.0.0 Roadmap
- Validate that all twelve codes have been exercised in at least one production service and that the mapping to HTTP status codes is stable and documented.
- Consider adding a
Codesregistry or lookup helper so transport layers can mapCode→ HTTP status without each service maintaining its own switch statement. - Evaluate whether additional convenience constructors (e.g.
PermissionDenied,Unauthorized) would reduce boilerplate enough to justify the addition. - Confirm that
ErrorContext()returning the live map is acceptable in all log-enrichment paths, or document that it must be treated as read-only by callers. - Achieve production validation of the duck-type logz bridge under concurrent load.
v0.9.0 rationale: The API is stable and intentional — designed through multiple architecture reviews and tested end-to-end via the todo-api POC (SQLite, RBAC, middleware stack, HTTP handlers). The module is not yet battle-tested in production for all edge cases, and the pre-1.0 designation preserves the option for minor API refinements based on real-world use.
Downloads