An actionable API error needs stable machine meaning separate from human explanation. Use the HTTP status for protocol-level semantics, a stable problem type or code for application behavior, structured field violations where relevant, and an instance or correlation identifier for support. Clients should never parse prose to decide whether to retry or highlight a field.
Give each layer one job
HTTP status answers the broad outcome: authentication required, authorization denied, resource absent, conflict, invalid request, overload, or server failure. RFC 9110 HTTP Semantics defines HTTP method and status semantics, and explains that HTTP presents a uniform interface with self-descriptive messages so clients, servers, proxies, and gateways can interoperate predictably. Respect those meanings so SDKs, intermediaries, and operators observe a coherent protocol.
The response body adds application detail. RFC 9457 Problem Details for HTTP APIs defines Problem Details members including type, status, title, detail, and instance, and allows extensions. It also recommends using URIs under your control to identify application-specific problem types and notes that human-readable strings such as title can vary by language negotiation. Use an HTTPS type URI you control as the stable machine identifier. Localize human-readable fields such as title. Do not expose stack traces, SQL, policy internals, or secrets in detail.
For validation, add a documented array of violations. Each item can carry a machine code and a field path using one consistent notation. A code such as too_short is more durable than an English sentence. Paths should refer to the public request shape, not internal object names. If several fields jointly violate a rule, point to the nearest shared object or omit the path and provide a form-level code.
Say what the client may do next
Retryability comes from the operation and failure, not merely whether the status starts with 5. When you can provide useful timing guidance, document how clients should wait before retrying. For a conflict, expose a stable reason such as version mismatch and, if safe, the current version. For asynchronous operations, consider returning an operation resource that clients can poll. For an ambiguous write, combine the error model with an idempotency-key contract.
Avoid a boolean retryable that can outlive nuanced server behavior. Prefer documented code-specific guidance: retry with backoff, refresh authentication once, fetch the latest representation, correct named fields, or contact support with the correlation ID. SDKs can map those codes into typed errors.
Evolve types without trapping clients
Clients should branch on the type or code they understand and fall back to status class for unknown problems. Add optional fields compatibly. Do not change the meaning of an existing type; publish a new type when the recovery action changes. Keep documentation examples and generated schemas aligned, and contract-test the error shapes at the API boundary.
Correlation identifiers must be safe to reveal and searchable by operators. Do not blindly reflect arbitrary client-supplied identifiers; if you accept correlation IDs from clients, validate them against your format and trust boundaries. Log the identifier with the internal exception, but return only sanitized public details.
Start with recovery decisions
Inventory the errors from one high-traffic endpoint and group them by what a client should do next. Assign an HTTP status and stable problem type to each group, define field violations, and write a fallback for unknown types. Test localization to prove no client depends on the title or detail. Then add dashboards by problem type; a stable client contract also becomes a better operational signal.
Test intermediaries and redaction
Exercise errors through the same gateway, cache, and client SDK used in production. Confirm content type, status, and problem body survive; correlation IDs are not duplicated; private upstream details are removed; and a cached error cannot cross users. Fuzz malformed JSON, large field values, invalid encodings, and unexpected exceptions so the error renderer itself never throws or reflects unsafe input. Verify unknown problem types still reach the client fallback.
Document the fallback response for any downstream dependency that cannot yet produce the contract. Reviewed September 2026.
Sources are linked throughout this guide. Product capabilities can change; consult the linked documentation for your deployment.
Read our editorial approach ↗