From golang-boost
Creates, wraps, and matches typed errors (BadRequest, NotFound, Conflict, etc.) in Go services using github.com/xgodev/boost/model/errors. Covers Echo error_handler and function publisher deadletter middleware matching, and registering custom errors for HTTP/gRPC status codes.
How this skill is triggered — by the user, by Claude, or both
Slash command
/golang-boost:boost-model-errorsThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
```go
import bootsterrors "github.com/xgodev/boost/model/errors"
return bootsterrors.NewBadRequest(err, "invalid payload") // wraps upstream err
return bootsterrors.BadRequestf("field %q is required", "id") // standalone
return bootsterrors.NewNotFound(err, "order not found")
return bootsterrors.NewConflict(err, "duplicate order id")
return bootsterrors.NewForbidden(err, "missing permission")
return bootsterrors.NewInternal(err, "downstream call failed")
return bootsterrors.NotValidf("invalid event data") // for function deadletter
return bootsterrors.Wrap(err, bootsterrors.NotValidf("...")) // wrap + classify
Two boost subsystems pattern-match on the unwrapped error type name:
| Matcher | Where | Routes by |
|---|---|---|
Echo error_handler plugin | HTTP responses (see boost-factory-echo) | *errors.NotFound → 404, *errors.BadRequest → 400, *errors.Conflict → 409, *errors.Forbidden → 403, *errors.Internal → 500, *errors.NotValid → 422 |
Function publisher middleware (deadletter mode) | Event handlers (see boost-bootstrap-middleware) | NotValid → notvalid deadletter topic; Internal → retry / alerting; etc. |
fmt.Errorf("%w", err) defeats both because errors.As(target *NotFound) can't unwrap an opaque wrapped error of unknown concrete type. Always use bootsterrors.Wrap.
The HTTP (Echo + function/CloudEvents) and gRPC error handlers resolve the status
via bootsterrors.Classify(err) Kind — registered custom errors first, then the
built-in Is* catalog. The Kind → HTTP status table lives in
model/restresponse (HTTPStatusFor) and is shared by Echo and the function
adapter; the Kind → gRPC code table lives in the gRPC server package.
For an application error that is not a boost type, register it once at boot
(before serving) against a semantic Kind. It then resolves to the right HTTP
status and gRPC code across all three transports — no per-transport wiring.
import bootsterrors "github.com/xgodev/boost/model/errors"
// "XptoError behaves like NotFound" → HTTP 404 / gRPC NotFound, everywhere.
bootsterrors.Register(ErrXpto, bootsterrors.KindNotFound) // matches via errors.Is
bootsterrors.RegisterMatch(func(err error) bool { // matches by type
_, ok := bootsterrors.Cause(err).(*MyTypedErr) // Cause, like Is* does
return ok
}, bootsterrors.KindConflict)
// Ignore: no opts == treat as success (HTTP 200 / gRPC OK) AND silence the log.
bootsterrors.Ignore(ErrNoise)
bootsterrors.Ignore(ErrAudit, bootsterrors.IgnoreSilenceLog) // status normal, just no log
bootsterrors.Ignore(ErrExpected, bootsterrors.IgnoreAsSuccess) // 200/OK, still logged
bootsterrors.Ignore(ErrBoth, bootsterrors.IgnoreAsSuccess, bootsterrors.IgnoreSilenceLog) // explicit both
Opts are OR-combined; passing none is equivalent to passing both. Ignore matches
via errors.Is; IgnoreMatch(func(error) bool, ...IgnoreOption) matches by predicate.
Kind values mirror the catalog: KindNotFound, KindBadRequest, KindNotValid,
KindConflict, KindAlreadyExists, KindForbidden, KindUnauthorized,
KindServiceUnavailable, KindNotImplemented, KindNotProvisioned,
KindNotSupported, KindNotAssigned, KindMethodNotAllowed,
KindTooManyRequests, KindTimeout, KindInternal (default).
Precedence in Classify: registered matchers (registration order, first wins) →
built-in Is* → KindInternal. The match predicate runs while the registry
lock is held — it must not call back into the registry (Register/Classify/
Ignore/…) or it self-deadlocks.
| Red flag | Fix |
|---|---|
fmt.Errorf("%w", err) for an error that flows through Echo or function middleware | bootsterrors.Wrap(err, bootsterrors.<Type>(...)) |
echo.NewHTTPError(404, "...") in a handler | bootsterrors.NewNotFound(err, "...") |
| Returning a raw upstream error to a handler caller | Wrap with the right bootsterrors.New<Type> so the matcher can route it |
Inventing a custom error struct for things model/errors already covers | Use the existing type — extending the catalog needs an upstream PR, not a local workaround |
| A genuinely app-specific error returning 500 because the handler doesn't know it | bootsterrors.Register(err, Kind…) / RegisterMatch(...) at boot so it maps to the right code in HTTP and gRPC |
| Editing the Echo/gRPC switch by hand to add a case for your error | Register it instead — the switch is now a shared Classify + Kind table |
npx claudepluginhub xgodev/boost --plugin golang-boostProvides Go error handling patterns: basic errors, wrapping with %w, sentinel errors, custom types, errors.Is, and Unwrap for robust apps.
Idiomatic Go error handling — creation, wrapping with %w, errors.Is/As/Join, custom types, sentinels, panic/recover, slog logging, HTTP middleware, and samber/oops for production errors. Apply when creating, wrapping, inspecting, or logging errors in Go codebases.
Guides Go error handling: sentinels vs custom types, fmt.Errorf wrapping (%w/%v), error flow, propagation across packages, errors.Is/As, with anti-pattern checker script.