RFC 9457 for REST APIs: Problem Details as an error contract
How to standardize HTTP error payloads for better DX, observability, and diagnostics.
Executive summary
How to standardize HTTP error payloads for better DX, observability, and diagnostics.
Last updated: 2/16/2026
Introduction: The asymmetry of success and failure
Most APIs are meticulously designed for the happy path. Request schemas are validated, response models are typed, and success status codes are correct. But when things go wrong, the quality collapses. Error responses return raw strings, generic messages like "Something went wrong", or—worse—a 200 OK with an error field buried inside the JSON body.
This asymmetry is expensive. Without a structured, predictable error format, every API consumer must write bespoke error-handling logic. Support teams spend hours on incidents because error logs contain no actionable context. Observability dashboards can't aggregate failures by category because there is no standard taxonomy.
RFC 9457 (Problem Details for HTTP APIs) solves this by defining a machine-readable, standardized envelope for API errors. It turns failure from an afterthought into a first-class contract.
The RFC 9457 standard: What it defines
RFC 9457 specifies a JSON (or XML) response format with a well-defined set of fields. The content type is application/problem+json.
Core fields
json{
"type": "https://api.example.com/errors/insufficient-funds",
"title": "Insufficient Funds",
"status": 422,
"detail": "Account 12345 has a balance of $10.00, but the transaction requires $25.00.",
"instance": "/transfers/txn-abc-123"
}| Field | Purpose | Key Rule |
|---|---|---|
type | A URI that uniquely identifies the category of the problem. | Must be stable and dereferenceable (ideally links to documentation or a runbook). This is the primary field for automation. |
title | A short, human-readable summary of the problem type. | Should be the same for all occurrences of this type. Do not include instance-specific data here. |
status | The HTTP status code (repeated for convenience). | Must match the actual HTTP status code of the response. |
detail | A human-readable explanation specific to this occurrence. | This is where instance-specific context goes: account IDs, amounts, field names. |
instance | A URI identifying the specific occurrence (for log correlation). | Typically the request path or a unique trace/correlation ID. |
Extension fields
RFC 9457 explicitly allows custom extension fields. This is where you add domain-specific context:
json{
"type": "https://api.example.com/errors/validation-failed",
"title": "Validation Failed",
"status": 422,
"detail": "The request body contains 2 validation errors.",
"instance": "/users/signup",
"errors": [
{ "field": "email", "message": "Must be a valid email address." },
{ "field": "password", "message": "Must be at least 8 characters." }
],
"traceId": "abc-def-123-456"
}The errors array and traceId are custom extensions—not defined by the RFC, but fully compliant.
Why this matters: Before and after
Without RFC 9457 (ad-hoc errors)
Different endpoints return errors in completely different formats:
json// Endpoint A
{ "error": "bad request" }
// Endpoint B
{ "code": 1001, "msg": "Invalid email" }
// Endpoint C
{ "success": false, "reason": "Not found" }Every API consumer must write three different error-parsing strategies. Observability tools can't aggregate these. Support teams can't triage efficiently.
With RFC 9457 (standardized errors)
Every endpoint returns the same structure. Consumers write one error handler. Dashboards aggregate by type. Support teams link directly to runbooks from the type URI.
Deepening the analysis: Designing an error taxonomy
The most impactful architectural decision when adopting RFC 9457 is designing your error taxonomy—the catalog of type URIs.
Principles for a good taxonomy
- Domain-level, not code-level. Types should represent business-domain failures (
insufficient-funds,order-already-shipped), not internal exceptions (NullPointerException,SequelizeValidationError). - Stable and versioned. Once a
typeURI is published, changing its meaning is a breaking change for consumers who automate based on it. - Never expose internal details. The
detailfield must be sanitized. Never leak stack traces, database table names, or internal service names in production error responses. - Link to runbooks. If the
typeURI is dereferenceable (e.g.,https://api.example.com/errors/rate-limit-exceeded), it should return a human-readable page explaining the error, possible causes, and resolution steps.
Example taxonomy structure
type URI | title | Typical status |
|---|---|---|
/errors/validation-failed | Validation Failed | 422 |
/errors/resource-not-found | Resource Not Found | 404 |
/errors/insufficient-funds | Insufficient Funds | 422 |
/errors/rate-limit-exceeded | Rate Limit Exceeded | 429 |
/errors/conflict-duplicate | Duplicate Resource Conflict | 409 |
/errors/unauthorized | Authentication Required | 401 |
/errors/forbidden | Insufficient Permissions | 403 |
/errors/service-unavailable | Upstream Service Unavailable | 503 |
When RFC 9457 accelerates delivery
Standardizing error contracts yields compounding returns across the organization:
- Support cost reduction: Teams can automate triage based on the
typefield instead of parsing free-text messages. - Observability improvement: Dashboards can aggregate errors by
typeandstatus, enabling trend analysis (e.g., "validation errors increased 40% after the last deploy"). - Consumer DX improvement: New API consumers learn one error format, write one error handler, and trust that it works consistently across all endpoints.
Decision prompts for your engineering context:
- Which error classes in your domain need stable
typeidentifiers for consumer automation (e.g., retry logic, user-facing messages)? - How will you version the error catalog without breaking existing clients?
- Which correlation fields (
traceId,requestId) are mandatory for support and audit workflows?
Tactical optimization plan
- Define a failure taxonomy by domain. Create a documented catalog of all problem types, grouped by business domain (Payments, Auth, Catalog).
- **Standardize
application/problem+jsonglobally.** Every error response across all API surfaces must use this content type. - **Instrument metrics by
typeand endpoint.** Track which problem types occur most frequently and on which endpoints. - Sanitize error payloads. Ensure no internal exception names, stack traces, SQL queries, or infrastructure details leak into production error responses.
- Document error examples in OpenAPI. Every endpoint's OpenAPI specification should include example
application/problem+jsonresponses for its expected failure modes. - **Train consumers on
type-based handling.** Consumers should branch their error-handling logic on thetypefield, not on string-matching thedetailmessage.
Reliability validations
Measure the success of RFC 9457 adoption by tracking:
- Mean diagnosis time per problem type: Has the time to diagnose issues decreased now that errors carry structured context?
- RFC 9457 compliance rate: What percentage of error responses return a complete, valid
application/problem+jsonenvelope? - Support ticket quality: Have support tickets decreased or improved in quality now that consumers receive actionable technical context?
Want to convert this plan into measurable execution with lower technical risk? Talk to a web specialist with Imperialis to design, implement, and operate this evolution.