RFC 9457 Problem Details for HTTP APIs

httpstatuses.net · 2026-07-23 · by Long Nguyen ·generic
RFC 9457 Problem Details guide with application/problem+json contracts, HTTP examples, OpenAPI 3.1 schemas, validation, and security.

RFC 9457 Problem Details for HTTP APIs

RFC 9457 Problem Details for HTTP APIs

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.

  • `type` is the resolved URI that clients use as the primary machine-readable identifier.
  • `title` is a stable human-readable summary of the type. `detail` explains one occurrence.
  • `instance` identifies one occurrence and can be a dereferenceable URI or an opaque URI.
  • Clients branch on the resolved `type`, not on `title` or `detail`.
  • 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" } ] }

    Copy validation example

    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

    Copy OpenAPI schema

    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.

    Copy type template

    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.

    | Case | Fixture | Assertion | | -------------------------- | ------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | | Producer: media type | A Problem Details JSON response | parseMediaType(contentType).essence === "application/problem+json" | | Producer: status agreement | Actual 422 with body status: 422 | body.status == null \|| body.status === response.status | | Client: optional members | Actual 400 with body {} | resolvedType === "about:blank"; missing members do not fail parsing | | Client: unknown extension | Add traceHint: "opaque" | Known behavior is unchanged; the extension is ignored | | Client: wrong types | {"status":"422","title":42} | Ignore both members; continue processing the object | | Client: relative URI | Base https://api.example.com/orders/123, type ../problems/conflict | new URL(type, base).href === "https://api.example.com/problems/conflict" | | Producer: secret-safe 5xx | Generated 500 body | Contains an opaque occurrence reference; does not match stack, SQL, credential, token, or internal-host fixtures |

    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 public `instance` URI.
  • 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`.
httpstatuses.net · 19 links

Comments (0)

No comments yet