RFC 9457 defines a standard error response body for HTTP APIs. JSON responses use the IANA-registered application/problem+json media type.
I use Problem Details after choosing the correct HTTP status code. The body explains the API-specific problem; it does not replace the status code understood by clients, proxies, caches, and monitoring tools. If the status is still unclear, start with the REST API status code chooser.
The producer and client contract
All five standard members are optional. Producers can send only the members that help, and an omitted type resolves to about:blank. The actual HTTP status is authoritative for the exchange; a body status is advisory and, when present, must match the status sent by the origin server.
typeis the resolved URI that clients use as the primary machine-readable identifier.titleis a stable human-readable summary of the type.detailexplains one occurrence.instanceidentifies one occurrence and can be a dereferenceable URI or an opaque URI.- Clients branch on the resolved
type, not ontitleordetail. - Clients ignore unrecognized extensions and any standard member whose JSON type is wrong. They continue processing the rest of the object.
- Clients should not automatically fetch type URIs during normal error handling. Developer tools can offer that as an explicit debugging action.
about:blank adds no semantics beyond the status code. A custom type is useful when clients need stable application-specific semantics, such as distinguishing an order-state conflict from other conflicts.
Problem Details keeps HTTP semantics and headers
The body does not replace status-specific headers. A 401 response still requires WWW-Authenticate. A 429 response can send Retry-After to tell the client how long to wait.
401 with an authentication challenge
HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
WWW-Authenticate: Bearer realm="orders"
{
"type": "https://api.example.com/problems/authentication-required",
"title": "Authentication required",
"status": 401
}
429 with retry timing
HTTP/1.1 429 Too Many Requests
Content-Type: application/problem+json
Retry-After: 60
{
"type": "https://api.example.com/problems/rate-limit",
"title": "Request rate limit exceeded",
"status": 429
}
500 without implementation secrets
HTTP/1.1 500 Internal Server Error
Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/internal-error",
"title": "Internal server error",
"status": 500,
"instance": "urn:example:problem:01K0ABCDEF8Z7R6W5V4T3S2Q1P"
}
The 500 response returns only a non-sensitive occurrence reference. Keep the stack trace, query text, credentials, internal hostnames, and debugging context in protected server logs.
Validation errors as an extension
A 422 Unprocessable Content response can add an errors extension with one entry per invalid field. This follows the extension pattern shown in RFC 9457 without turning each field error into a separate top-level problem.
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
"type": "https://api.example.com/problems/validation-error",
"title": "Request validation failed",
"status": 422,
"errors": [
{ "detail": "must be a valid email address", "pointer": "/email" },
{ "detail": "must be 18 or greater", "pointer": "/age" }
]
}
An errors collection represents multiple occurrences of one problem type. When several problems have disparate types, return the most relevant or urgent problem. Avoid a generic envelope that mixes unrelated types because it does not map cleanly to HTTP semantics. Use 400 Bad Request when the request itself is malformed; use 422 when validly encoded content cannot be processed.
OpenAPI 3.1 schemas
The base schema keeps all standard members optional and allows problem-specific extensions. The validation subtype fixes its identity and defines the errors extension. Use schemas to check producers; RFC 9457 still requires tolerant clients to ignore wrong-typed standard members.
openapi: 3.1.0
info:
title: Example API
version: 1.0.0
paths: {}
components:
schemas:
Problem:
type: object
properties:
type:
type: string
format: uri-reference
default: about:blank
title:
type: string
status:
type: integer
minimum: 100
maximum: 599
detail:
type: string
instance:
type: string
format: uri-reference
additionalProperties: true
ValidationProblem:
allOf:
- $ref: '#/components/schemas/Problem'
- type: object
required: [type, errors]
properties:
type:
type: string
format: uri-reference
const: https://api.example.com/problems/validation-error
errors:
type: array
minItems: 1
items:
type: object
required: [detail, pointer]
properties:
detail:
type: string
pointer:
type: string
format: json-pointer
additionalProperties: false
Problem type document template
Publish a stable type URI with the type's title, recommended status, meaning, remediation, and extension schema. This template documents a type; it is not a Problem Details response body.
typeURI: https://api.example.com/problems/order-conflict
title: Order state conflict
recommendedStatus: 409
meaning: The requested transition conflicts with the current order state.
remediation: Fetch the latest order state and choose a valid transition.
extensions:
currentState:
type: string
description: The order state that blocked the transition.
Keep the URI under your control and stable over time. Changing the type URI changes the problem's identity and is a breaking change for clients that branch on it. Check the IANA HTTP Problem Types registry before defining a type intended for broad reuse.
Contract-test matrix
Run these checks at the HTTP boundary. The assertion column is intentionally close to test code so the cases can be moved into the API's existing test runner.
Security and privacy
- Do not expose stack traces, SQL, internal hostnames, secrets, or authorization rules that help an attacker.
- Do not put personal data or sensitive identifiers in
detail, extensions, or a publicinstanceURI. - Protect dereferenceable instance resources with the same authorization checks as the underlying data.
- Log private debugging details server-side and return a safe occurrence identifier to the client.
RFC 9457's security considerations specifically warn about implementation leaks, privacy risks, and disagreement between the actual response status and the advisory member.
Primary references
- RFC 9457: Problem Details for HTTP APIs — the current standard, replacing RFC 7807.
- RFC 9110: HTTP Semantics — current HTTP status and response-header semantics.
- IANA HTTP Status Code Registry — registered status codes and references.
- IANA application/problem+json registration — the registered JSON media type.
- RFC 6585 section 4 — 429 Too Many Requests and
Retry-After.