Create a stable error interface that clients can depend on without parsing prose. Preserve compatibility where practical and make every change explicit.
Workflow
Inventory current errors. Trace handlers, middleware, validators, domain errors, and exception fallbacks. Record status, body shape, machine code, message source, retry behavior, and whether sensitive detail can leak.
Define one envelope. Use the repository's conventions where they exist; otherwise design a minimal shape such as:
{ "error": { "code": "ORDER_ALREADY_PAID", "message": "This order has already been paid.", "request_id": "req_123", "fields": [{ "path": "email", "code": "INVALID_FORMAT" }], "retryable": false } }Omit optional fields when irrelevant. Keep machine codes stable, uppercase, and domain-specific.
Map semantics deliberately. Assign statuses by protocol meaning: authentication, authorization, missing resource, conflict, validation, rate limit, upstream failure, and unexpected server error. Distinguish a safe retry from a permanent client error; add
Retry-Afteronly when the server can provide meaningful guidance.Separate public and internal detail. Return safe messages. Log stack traces and internal context with the same request or correlation ID. Never expose SQL, filesystem paths, tokens, provider payloads, or raw exceptions.
Model field errors structurally. Use stable field paths and codes. Do not concatenate multiple validation problems into one sentence clients must parse.
Preserve compatibility. Build a before/after mapping. If existing clients depend on a legacy field, introduce the new envelope additively or version the breaking change; do not silently rename it.
Implement centrally. Prefer typed domain errors plus one translation layer over hand-built responses in every handler. Update the OpenAPI schema and SDK types from the same contract.
Add contract tests. Cover representative errors, the fallback 500 path, redaction, request IDs, field validation, and retry headers. Assert codes and structure rather than mutable message wording unless the message itself is contractual.
[!WARNING] Never let clients branch on
message. Prose changes for clarity and localization; machine codes are the compatibility surface.
Output
Return:
- the proposed error schema and code-naming rules
- a current-to-target mapping table for every discovered error path
- implementation edits to the central translator and typed errors
- updated API schema or documentation
- contract tests proving status, code, redaction, field details, retry semantics, and fallback behavior
- compatibility or rollout notes for existing clients