Structured application errors with typed codes, cause chaining, key-value context fields, and zero-import logz enrichment bridge. What's included: - `*Err` type implementing error, errors.Unwrap, json.Marshaler, ErrorCode(), and ErrorContext() - Twelve typed Code constants aligned with gRPC canonical status names - New / Wrap factory constructors plus InvalidInput / NotFound / Internal convenience constructors - Builder methods WithContext and WithError for attaching structured fields and causes - Duck-typed ErrorCode() / ErrorContext() bridge so logz auto-enriches log records without an import Tested-via: todo-api POC integration Reviewed-against: docs/adr/
3.5 KiB
3.5 KiB
Changelog
All notable changes to this module will be documented in this file.
The format is based on Keep a Changelog, and this module adheres to Semantic Versioning.
0.9.0 - 2026-03-18
Added
Code— string type alias for machine-readable error categories with stable wire values aligned to gRPC canonical status names- Thirteen typed
Codeconstants:ErrInvalidInput(INVALID_ARGUMENT),ErrUnauthorized(UNAUTHENTICATED),ErrPermissionDenied(PERMISSION_DENIED),ErrNotFound(NOT_FOUND),ErrAlreadyExists(ALREADY_EXISTS),ErrGone(GONE),ErrPreconditionFailed(FAILED_PRECONDITION),ErrRateLimited(RESOURCE_EXHAUSTED),ErrCancelled(CANCELLED),ErrInternal(INTERNAL),ErrNotImplemented(UNIMPLEMENTED),ErrUnavailable(UNAVAILABLE),ErrDeadlineExceeded(DEADLINE_EXCEEDED) Code.Description() string— human-readable description for each code; unknown codes return their raw string valueErrstruct — structured error type carrying aCode, human-readable message, optional cause, and optional key-value context fieldsNew(code Code, message string) *Err— primary factory constructor; no cause setWrap(code Code, message string, err error) *Err— factory constructor that wraps an existing error as the causeInvalidInput(msg string, args ...any) *Err— convenience constructor forErrInvalidInput; message formatted withfmt.SprintfNotFound(msg string, args ...any) *Err— convenience constructor forErrNotFoundInternal(msg string, args ...any) *Err— convenience constructor forErrInternal(*Err).WithContext(key string, value any) *Err— chainable builder method to attach a key-value context field; overwrites existing value for the same key(*Err).WithError(err error) *Err— chainable builder method to set or replace the cause(*Err).Error() string— implements theerrorinterface; format:"CODE: message → cause"(*Err).Unwrap() error— implementserrors.Unwrap, enablingerrors.Isanderrors.Asto walk the full cause chain(*Err).Code() Code— returns the typed error code(*Err).Message() string— returns the human-readable message(*Err).Fields() map[string]any— returns a safe shallow copy of all attached context fields; always non-nil(*Err).Detailed() string— verbose debug string including code, message, cause, and fields(*Err).ErrorCode() string— duck-type bridge satisfying logz's internalerrorWithCodeinterface; enables automaticerror_codelog field enrichment without importing logz(*Err).ErrorContext() map[string]any— duck-type bridge satisfying logz's internalerrorWithContextinterface; returns the live internal map (read-only)(*Err).MarshalJSON() ([]byte, error)— implementsjson.Marshaler; output:{"code":"...","message":"...","fields":{...}}
Design Notes
- Error codes are string type aliases with stable wire values — safe to serialize, persist, and compare across service versions; HTTP status mapping is deliberately excluded and belongs in the transport layer.
*Errsatisfieserrors.Unwrap,json.Marshaler, and two private duck-type interfaces (ErrorCode,ErrorContext) that logz inspects viaerrors.As, decoupling the two packages without any import between them.- Zero external dependencies — stdlib only (
encoding/json,fmt); Tier 0 of the micro-lib stack.