Documentation
¶
Overview ¶
Package errs — provides package-level introspection helpers that walk a cause chain and read fields from the deepest *Error encountered. Consumers of pkg/v1/errs use re-exports of these.
Package errs — defines the dotted-quad Code type introduced by ADR 0005. Layout: MM.LL.PP.SS over uint32 — Major.Layer.Package.Serial. Codes are comparable, ordered, map-keyable, and const-expressible via hex literals (Pack is a runtime constructor only).
Code is a packed uint32 (shifts/masks only), so it is fully portable across 32- and 64-bit GOARCH — there is no build constraint here. Validation bounds every Code to uint32 ≤ 0x7FFFFFFF (validate.go), so the rare int(code) cast round-trips losslessly even where int is 32-bit.
Package errs — meta-codes (Layer=0 reserved for this file). Used in Define panic messages and in internal bootstrap errors (newValidationError). These codes are documentary: they are NOT returned from emitter APIs as sentinel *Error values.
Layer=0 is ENFORCED reserved for this package by validateDefineArgs — any Define call with Layer==0 AND code not in this whitelist will panic.
Constants are typed as Code so Define call sites accept them directly and downstream comparisons with Error.Code() are type-safe.
Package errs — defines the SDK-wide typed Error plus the Define and Wrap constructors. Consumers never import this package directly — they introspect errors through github.com/kitsunium/sdk/pkg/v1/errs.
Package errs — defines the closed FieldValue union used to attach structured metadata to an Error without opening an `any` back door. FieldValue is a transport + textual-restitution contract, NOT a vehicle for strongly-typed reconstruction on the consumer side — StringValue is the only value accessor exposed in this MR.
Package errs — provides ParseCode, the strict canonical parser for dotted-quad Code strings produced by Code.String(). The parser is intentionally NOT compatible with the Padded() form — that would make two textual representations round-trip to the same Code, violating the single-canonical-form invariant declared in ADR 0005 §3.2.
Package errs — hosts the PrefixMatcher target used by errors.Is for CIDR-style Code matching. PrefixMatcher deliberately does NOT implement the `error` interface so it cannot escape into error chains as a return value — callers pass it only to errors.Is.
Package errs — placeholder companion to the SDK-wide AST audit (registry_external_test.go). There is no runtime registry today; the code allocation table lives in ADR 0002 and the audit test embeds it.
Package errs — holds the wrap-trail mechanism introduced by ADR 0005. Trail carries the sites a *Error was wrapped through; origin wins on Code() per ADR 0002, but Trail() / HasCode() traverse the full list of wrap sites to help observability and matching.
Package errs — TrailOf exposes the wrap-trail codes of the deepest *Error in a chain, the read-side companion to the Of-family accessors, enabling structured log decomposition without reparsing the rendered bracket header.
Package errs — centralises the runtime structural checks applied by Define. Factoring the logic out of Define lets tests cover every rule as a plain function call without subprocess fixtures for package-init panics.
Package errs — hosts WrapParams in its own file so error.go keeps a single exported struct (one-struct-per-file convention).
Index ¶
- func ExitCodeOf(err error) int
- func HTTPStatusOf(err error) int
- func HasCode(err error, c Code) bool
- func HasReason(err error, reason string) bool
- func PrivateOf(err error) string
- func PublicOf(err error) string
- func ReasonOf(err error) (reason string, ok bool)
- func RegistryMarker() string
- type Code
- type DefineOption
- type Error
- func Define(code Code, reason, public, private string, opts ...DefineOption) *Error
- func NewError(code Code, reason, public, private string, opts ...DefineOption) *Error
- func NewRuntime(code Code, reason, public, private string, fields ...FieldValue) *Error
- func Wrap(cause error, params WrapParams, fields ...FieldValue) *Error
- func (e *Error) Code() Code
- func (e *Error) Error() string
- func (e *Error) ExitCode() int
- func (e *Error) Fields() []FieldValue
- func (e *Error) HTTPStatus() int
- func (e *Error) Is(target error) bool
- func (e *Error) Private() string
- func (e *Error) Public() string
- func (e *Error) Reason() string
- func (e *Error) Source() error
- func (e *Error) Trail() []Code
- func (e *Error) TrailTruncated() bool
- func (e *Error) Unwrap() error
- type FieldValue
- func Bool(key string, val bool) FieldValue
- func FieldsOf(err error) []FieldValue
- func Float(key string, val float64) FieldValue
- func Int(key string, val int) FieldValue
- func Int64(key string, val int64) FieldValue
- func NewFieldValue(key, val string) FieldValue
- func String(key, val string) FieldValue
- type Layer
- type Major
- type PkgCode
- type PrefixMatcher
- type Serial
- type WrapParams
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExitCodeOf ¶
ExitCodeOf walks the chain and returns the deepest *Error.ExitCode().
func HTTPStatusOf ¶
HTTPStatusOf walks the chain and returns the deepest *Error.HTTPStatus().
func HasCode ¶
HasCode returns true if any *Error in err's chain has code == c OR any trail entry matches c. The walk recurses through BOTH single-error wrappers (Unwrap() error) AND multi-error wrappers (Unwrap() []error, e.g. errors.Join). Time complexity: O(total_errors + total_trail_lengths).
func PrivateOf ¶
PrivateOf walks the chain and returns the deepest *Error.Private, or "" when no *Error is present in the chain. DIAGNOSTIC-ONLY: never expose in HTTP/gRPC responses or any user-facing surface. Intended for operator tooling and log correlation.
func PublicOf ¶
PublicOf walks the Unwrap chain and returns the deepest *Error.Public, or "" when no *Error is present in the chain.
func RegistryMarker ¶
func RegistryMarker() string
RegistryMarker returns the registry sentinel so external callers (and the audit test itself) can confirm the package is the one expected to own the SDK-wide code allocation audit.
Types ¶
type Code ¶
type Code uint32
Code packs a 4-byte dotted identifier (MM.LL.PP.SS) as uint32. See ADR 0005 for the registry.
const ( MaskByMajor Code = 0xFF_00_00_00 // /8 — all codes sharing Major MaskByLayer Code = 0xFF_FF_00_00 // /16 — all codes sharing Major+Layer MaskByPackage Code = 0xFF_FF_FF_00 // /24 — all codes sharing Major+Layer+Package MaskExact Code = 0xFF_FF_FF_FF // /32 — exact match only )
CIDR-style mask constants for prefix matching via NewPrefixMatcher.
const ( // CodeInvalidCode identifies a Define call whose numeric code is zero, // overflows int32-positive range, or violates the Layer=0 reserved rule. CodeInvalidCode Code = iota + 0x00_00_00_01 // 0.0.0.1 // CodeInvalidReason identifies a Define call whose Reason is empty or // does not match the SCREAMING_SNAKE convention. CodeInvalidReason // 0.0.0.2 // CodeInvalidPublic identifies a Define call whose Public message is // empty, exceeds 120 runes, or contains a newline. CodeInvalidPublic // 0.0.0.3 // CodeInvalidPrivate identifies a Define call whose Private message is // empty. Introduced by ADR 0005 to close the validate.go bug where // CodeInvalidPublic was erroneously cited for Private-field failures. CodeInvalidPrivate // 0.0.0.4 // CodeInvalidCodeString identifies a ParseCode failure (malformed // canonical dotted-quad input). CodeInvalidCodeString // 0.0.0.5 // CodeInvalidWrapParams identifies a Wrap-time validation failure on // caller-supplied WrapParams. Wrap returns an *Error carrying this // code instead of panicking (runtime path, not init-time). CodeInvalidWrapParams // 0.0.0.6 )
func Pack ¶
Pack constructs a Code from its four octets. RUNTIME only — sentinel constants MUST use hex literals so they stay const-expressible.
func ParseCode ¶
ParseCode parses the canonical "M.L.P.S" form produced by Code.String().
Rules (any violation returns an *Error with CodeInvalidCodeString):
- Exactly 4 dot-separated segments.
- Each segment is 1 to 3 ASCII digits.
- No leading zero in any segment ("001", "01", "0001" → REJECTED). This excludes the Padded() form ("001.001.001.001") as input, so the canonical form is the only textual key that maps to a Code.
- Each segment's numeric value is in [0, 255].
- No leading/trailing whitespace, no sign character, no empty segment.
func TrailOf ¶
TrailOf returns the wrap-trail codes of the deepest *Error in err's chain, newest wrap last, or nil when err carries no *Error.
The trail mirrors the wrap-site chain accumulated as the error was wrapped (the origin's own Code is NOT included — it is reached via CodeOf).
type DefineOption ¶
type DefineOption func(e *Error)
DefineOption tunes an Error at Define time. Options compose left-to-right.
func WithExitCode ¶
func WithExitCode(code int) DefineOption
WithExitCode overrides the default POSIX exit code (70) for an Error.
func WithHTTPStatus ¶
func WithHTTPStatus(status int) DefineOption
WithHTTPStatus overrides the default HTTP status (500) for an Error.
type Error ¶
type Error struct {
// contains filtered or unexported fields
}
Error is the SDK-wide typed error. Fields are unexported — consumers obtain values via the getter methods on *Error or via the Of-accessors in github.com/kitsunium/sdk/pkg/v1/errs. Instances are immutable after construction: Wrap returns a new *Error, never mutates the input.
func Define ¶
func Define(code Code, reason, public, private string, opts ...DefineOption) *Error
Define registers a sentinel-style *Error at package init. It panics (with a message citing one of the documentary meta-codes 0.0.0.1..6) when validateDefineArgs returns non-nil, so structural mistakes surface at program start rather than at the first emission.
func NewError ¶
func NewError(code Code, reason, public, private string, opts ...DefineOption) *Error
NewError is a tooling-friendly alias for Define. Prefer Define at call sites for consistency; NewError exists so code generators and lints expecting a NewXxx constructor on exported types find one.
func NewRuntime ¶ added in v0.1.6
func NewRuntime(code Code, reason, public, private string, fields ...FieldValue) *Error
NewRuntime constructs an *Error at RUNTIME without panicking. It is the counterpart to Define for callers that get no build-time AST audit — principally external SDK consumers reaching this through pkg/v1/errs.New. Where Define panics at package init on a malformed sentinel (caught by the registry AST audit before the binary ships), NewRuntime mirrors Wrap's runtime policy: a structural failure returns a typed validation *Error (CodeInvalidCode / Reason / Public / Private) preserving the specific rule that failed, so the result is always a usable, introspectable SDK error and never nil. Fields are defensively copied. HTTP/exit overrides default (500 / 70); use Wrap with WrapParams.ExitCode or a sibling Define sentinel when an override is needed.
func Wrap ¶
func Wrap(cause error, params WrapParams, fields ...FieldValue) *Error
Wrap attaches a cause to a new *Error with origin-wins semantics. Behaviour contract (see ADR 0005 §3.6): 1. cause == nil (interface nil) → stdlib path, source = nil 2. cause == (*Error)(nil) typed-nil → stdlib path, source = nil 3. cause == (*T)(nil) typed-nil of non-*Error → stdlib path, source preserved 4. cause is *Error (directly or behind a stdlib wrapper) → origin-wins, params.Code is APPENDED TO THE TRAIL (trail entry 0 is the origin) 5. cause is other stdlib error → params.Code is origin, trail stays empty
Runtime policy (v5 HIGH fix): bad WrapParams at runtime does NOT panic; the returned *Error carries CodeInvalidWrapParams and preserves cause.
func (*Error) Error ¶
Error returns the neutral stable form "[<code> <REASON>] <public>". It never includes Private content nor Fields, so callers may safely bubble err.Error() across any boundary without leaking diagnostic data.
When the trail is non-empty, wrap-site codes are rendered between the origin code and the Reason with ASCII "<-" separators, e.g.:
[0.3.2.1 <- 1.2.0.3 JSON_MARSHAL_FAILED] invalid input
Truncated trails append " (truncated)" before the Reason marker.
func (*Error) Fields ¶
func (e *Error) Fields() []FieldValue
Fields returns a defensive copy of the structured metadata attached to this Error. Mutating the returned slice has no effect on the Error.
func (*Error) HTTPStatus ¶
HTTPStatus returns the per-error override if set, otherwise 500.
func (*Error) Is ¶
Is implements the errors.Is protocol. Three matching modes:
1. target is *PrefixMatcher → match if origin code OR any trail entry satisfies the CIDR-style mask (ADR 0005 prefix routing). 2. target is *Error with non-zero Code → match when the two share the same (Code, Reason). This lets errors.Is(err, sentinel) succeed even when err is a freshly-constructed Wrap result — the typed sentinel and the wire sentinel have identical Code+Reason by construction, and semantic equivalence is what callers expect. The Reason check defuses a hypothetical Code-collision (the registry audit is the primary guard; this is belt-and-suspenders). 3. anything else → pointer equality (stdlib default).
func (*Error) Private ¶
Private returns this Error's log-only detailed message. Never expose the return value over any user-facing surface.
func (*Error) Trail ¶
Trail returns a defensive copy of the wrap-site chain (newest last). The origin's code is NOT in the trail — it lives in Code().
func (*Error) TrailTruncated ¶
TrailTruncated reports whether the trail's middle links have been dropped due to exceeding maxTrailLen. The flag is MONOTONIC: once set by appendTrail, it propagates unchanged to every subsequent wrap.
type FieldValue ¶
type FieldValue struct {
// contains filtered or unexported fields
}
FieldValue is an immutable typed key/value pair attached to an *Error. Use the exported constructors (String, Int, Bool, Float, NewFieldValue) to create a valid FieldValue — the zero value is invalid and must never be passed across the API.
func Bool ¶
func Bool(key string, val bool) FieldValue
Bool builds a FieldValue holding a boolean value.
func FieldsOf ¶
func FieldsOf(err error) []FieldValue
FieldsOf collects the FieldValues attached to every *Error along the chain and returns them ordered inner-to-outer (oldest cause first, newest wrapper last). The returned slice is a defensive copy.
func Float ¶
func Float(key string, val float64) FieldValue
Float builds a FieldValue holding a float64 value.
func Int ¶
func Int(key string, val int) FieldValue
Int builds a FieldValue from a plain int. Matches the slog / zap convention (both expose Int(key, int) that widens internally) so callers do not write int64(…) at every site. For pre-widened int64 payloads use Int64.
func Int64 ¶
func Int64(key string, val int64) FieldValue
Int64 builds a FieldValue from a 64-bit integer. Provided explicitly because Go does not support function overloading — callers that hold an int64 already (no upcast needed) reach for this constructor, while the common int case stays on Int.
func NewFieldValue ¶
func NewFieldValue(key, val string) FieldValue
NewFieldValue builds a string-typed FieldValue. Provided as a generic constructor for tooling that expects a New-prefixed factory; for common cases prefer the dedicated String/Int/Bool/Float helpers.
func String ¶
func String(key, val string) FieldValue
String builds a FieldValue holding a string value.
func (FieldValue) Key ¶
func (f FieldValue) Key() string
Key returns the identifier under which this FieldValue was recorded.
func (FieldValue) StringValue ¶
func (f FieldValue) StringValue() string
StringValue returns a deterministic textual rendering of the payload suitable for log lines and error dumps. Not guaranteed to be machine- parseable back into the original type — by design the consumer contract stops at textual observation.
type Layer ¶
type Layer uint8
Named octet types prevent positional-argument footguns in Pack. PkgCode is spelled out (not `Pkg`) so callers keep `pkg` as an ordinary variable name without shadowing.
type Major ¶
type Major uint8
Named octet types prevent positional-argument footguns in Pack. PkgCode is spelled out (not `Pkg`) so callers keep `pkg` as an ordinary variable name without shadowing.
type PkgCode ¶
type PkgCode uint8
Named octet types prevent positional-argument footguns in Pack. PkgCode is spelled out (not `Pkg`) so callers keep `pkg` as an ordinary variable name without shadowing.
type PrefixMatcher ¶
type PrefixMatcher struct {
// contains filtered or unexported fields
}
PrefixMatcher is a NON-ERROR sentinel used ONLY as a target for errors.Is. Callers build it via NewPrefixMatcher and pass it to errors.Is; the matching logic lives on (*Error).Is (see error.go, added in W4).
func NewPrefixMatcher ¶
func NewPrefixMatcher(prefix, mask Code) *PrefixMatcher
NewPrefixMatcher constructs a PrefixMatcher usable with errors.Is to match all Codes sharing a given bit-prefix (defined by the mask). Example: all codes originating from pkg/v1/* →
errors.Is(err, errs.NewPrefixMatcher(0x01_00_00_00, errs.MaskByMajor))
func (*PrefixMatcher) Error ¶
func (p *PrefixMatcher) Error() string
Error implements the `error` interface so PrefixMatcher is usable as a target for `errors.Is`. Returning an error-looking string is the ONLY way Go's errors.Is can accept a non-sentinel target; callers MUST never return a *PrefixMatcher from a function as an error. A follow-up linter rule will catch accidental escapes.
func (*PrefixMatcher) Mask ¶
func (p *PrefixMatcher) Mask() Code
Mask exposes the matcher's mask for internal callers.
func (*PrefixMatcher) Prefix ¶
func (p *PrefixMatcher) Prefix() Code
Prefix exposes the matcher's prefix for internal callers (e.g., the (*Error).Is method) without leaking the field directly.
func (*PrefixMatcher) String ¶
func (p *PrefixMatcher) String() string
String returns a diagnostic representation of the matcher.
type Serial ¶
type Serial uint8
Named octet types prevent positional-argument footguns in Pack. PkgCode is spelled out (not `Pkg`) so callers keep `pkg` as an ordinary variable name without shadowing.
type WrapParams ¶
type WrapParams struct {
// Code is the dotted-quad identifier assigned to the wrapping Error.
Code Code
// Reason is the SCREAMING_SNAKE stable identifier of the wrapping Error.
Reason string
// Public is the wire-safe message (string literal at source level).
Public string
// Private is the log-only detailed message.
Private string
// ExitCode optionally overrides the POSIX exit status of the wrapping
// Error (default 70 EX_SOFTWARE); the zero value keeps the default. It
// lets a stdlib cause be wrapped into an Error that carries the same
// exit semantics as a sibling errs.Define sentinel — the origin-wins
// path already inherits a cause Error's exit override, but the
// stdlib-cause path has no Error to inherit from.
ExitCode int
}
WrapParams groups the extra metadata Wrap needs when the cause is NOT already an *Error. Keeping them in a struct stays below the SDK's 5-parameter ceiling for Wrap and gives call sites named fields.