Context
Errors were thrown as rawError objects and strings, and each package shaped them differently. The envelope and the ten kinds are fixed in
0140, and machine codes are snake_case (0231). The owner
answered on 2026-10-20 that one package holds the base error and the platform hooks for each runtime.
Decision
- Package and category.
@stackra/errorsis a foundation package. It has these entries, and no others unless a later ADR adds one:core,react,native,nodeandtesting. - core:
StackraError. The base class carries:category: one of the ten categories of 0140 (the envelope’s field name);code: a snake_case machine code;retryable;cause;details;fieldErrors;- an i18n message key derived from the code (0162);
correlationId;serialize()to theErrorEnvelopeof 0140, anddeserialize()back.
- Every error extends the base. All package, app and service errors extend
StackraError. Code never throws a rawErroror a string. A lint rule enforces this, and the code-standards steward checks it in review. - react.
ErrorBoundary, the React Router 7 routeerrorElement, auseErrorHandlerhook, and a mapping from category to user experience. The mapping includes toasts, and anentitlement_requirederror shows the upgrade path (0139). - native. A React Native boundary, the
ErrorUtilsglobal handler, and handlers for unhandled promise rejections. - node. Process-level handlers for uncaught exceptions and unhandled rejections.
- testing. Helpers that assert a category, a code and an envelope, so tests check the contract and not the message text.
- Reporter port. Error tracking is a port with a Sentry driver. Before any report leaves the process, personal data is scrubbed (classification of 0134 applies). Reports carry fingerprints. The port is wired through the logger (0147) and the observability package (0073).
Consequences
- A thrown error always has a category and a code, so the transport mappings of 0140 never meet an unknown error.
- A client sees the same envelope whether the error came from a service, an app or the platform.
- Adding an error means choosing one of the ten kinds. A new kind is an ADR change (0140).
Enforcement
planned — a house lint rule forbidsthrow new Error( and throw "..." in packages, apps and services, and the code-standards steward reviews
the rule’s exceptions. The envelope round-trip is tested in core, and the category-to-UX mapping is tested in react.
Alternatives
- Keep raw
Errorobjects and strings: rejected; the envelope could not be generated from them. - A separate error package per runtime without a base: rejected; each runtime would shape errors differently.
Supersedes and sources
Supersedes: none. Builds on 0140. Sources: owner answer on@stackra/errors (2026-10-20); the
error kinds and snake_case rule of 0140 and 0231.