feat: add WithPlatformCode for domain-level error identity Adds an optional PlatformCode field to *Err, decoupled from the transport-level Code. Code drives HTTP/gRPC status mapping; PlatformCode is a stable domain identifier for consuming applications (e.g. a frontend performing i18n) to map errors to localised messages. Platform codes are optional — errors without a user-actionable meaning (500s, infrastructure failures, auth rejections) carry none. Fully backwards-compatible: no existing signatures or JSON output changed for errors without a platform code. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Reviewed-on: #2 Reviewed-by: Rene Nochebuena <rene@noreply.nochebuena.dev> Co-authored-by: Claude Code <claude@nochebuena.dev> Co-committed-by: Claude Code <claude@nochebuena.dev>
4.6 KiB
4.6 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.10.0 - 2026-03-25
Added
(*Err).WithPlatformCode(code string) *Err— chainable builder method to attach a platform-level error code; returns the receiver for chaining(*Err).PlatformCode() string— getter that returns the platform code, or an empty string if none was setplatformCodefield inMarshalJSONoutput — serialised as"platformCode"and omitted when empty (omitempty)
Design Notes
- Platform codes operate at the domain/system layer and are intentionally decoupled from the transport-level
Code.Codedrives HTTP status mapping and gRPC status codes;PlatformCodeis a stable semantic identifier for the consuming application (e.g. a frontend performing i18n). - Platform codes are optional. Errors that do not have a user-actionable meaning (500 internal errors, infrastructure failures, authentication rejections) should not carry one.
- No existing behaviour changed —
Code,Error,Unwrap,WithContext,MarshalJSON(for errors without a platform code) are all backwards-compatible.
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.