feat(xerrors): initial stable release v0.9.0

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/
This commit is contained in:
2026-03-18 13:09:31 -06:00
commit 3cc36801a1
14 changed files with 1118 additions and 0 deletions

43
doc.go Normal file
View File

@@ -0,0 +1,43 @@
/*
Package xerrors provides structured application errors with stable machine-readable
codes, human-readable messages, cause chaining, and key-value context fields.
Each error carries a [Code] that maps to a well-known category (invalid input,
not found, internal, etc.) and is stable across versions — safe to persist,
transmit in API responses, or switch on programmatically.
# Basic usage
err := xerrors.New(xerrors.ErrNotFound, "user not found")
// With cause chaining
err := xerrors.Wrap(xerrors.ErrInternal, "failed to query database", dbErr)
// Convenience constructors
err := xerrors.NotFound("user %s not found", userID)
// Builder pattern
err := xerrors.New(xerrors.ErrInvalidInput, "validation failed").
WithContext("field", "email").
WithContext("tag", "required")
# Cause chaining
[Err.Unwrap] is implemented, so [errors.Is] and [errors.As] walk the full
cause chain:
if errors.Is(err, io.ErrUnexpectedEOF) { ... }
var e *xerrors.Err
if errors.As(err, &e) {
log.Println(e.Code())
}
# Structured logging (duck-typing bridge)
[Err.ErrorCode] and [Err.ErrorContext] satisfy the private interfaces that logz
defines internally. Passing an *Err to logger.Error automatically enriches the
log record with error_code and context fields — without xerrors importing logz
or logz importing xerrors.
*/
package xerrors