---
name: http-problem-details
description: Design, generate, and consume RFC 9457 problem details for HTTP APIs (application/problem+json, application/problem+xml). Use when implementing or reviewing API error responses, standardizing error bodies, defining new error/problem types, or parsing errors in an HTTP client — including "return a proper JSON error", "structure our API errors", or any mention of RFC 7807, RFC 9457, or problem+json, even if the user doesn't say "problem details". Not for choosing HTTP status codes in general or debugging application logic.
license: See source document (RFC 9457, IETF Trust, BSD-licensed code components)
metadata:
  source: "RFC 9457: Problem Details for HTTP APIs (July 2023, obsoletes RFC 7807)"
---

# HTTP Problem Details (RFC 9457)

Problem details carry machine-readable error information in HTTP response
content so APIs don't invent their own error formats. The JSON serialization
uses the `application/problem+json` media type; an equivalent XML format uses
`application/problem+xml`. RFC 9457 obsoletes RFC 7807 with the same format —
it adds a problem-type registry, guidance for multiple problems, and guidance
for non-dereferenceable type URIs — so treat "RFC 7807" requests as this format.

RFC 2119 keyword strengths (MUST / SHOULD / MAY) below are the source
document's own strengths. Do not promote or weaken them.

## When to use problem details — and when not to

Use them when a 4xx/5xx status code alone cannot convey enough for a machine
client to act on the error. Do **not** use them when:

- The defined HTTP status code already covers the situation with no extra
  detail needed. Truly generic problems are better expressed as plain status
  codes — e.g. "write access disallowed" is unnecessary because 403 Forbidden
  on a PUT is self-explanatory.
- The response is still a representation of a resource — prefer describing the
  problem in that application's format.
- The application already has a domain-specific error format. Problem details
  exist to avoid inventing new "fault"/"error" formats, not to replace existing
  ones. (It is still possible to add problem details support to an existing
  API via HTTP content negotiation, e.g. the Accept request header.)

Never redefine the semantics of existing HTTP status codes instead of using
problem details. Problem details fit any status code but most naturally 4xx/5xx.

Problem details expose detail about the **HTTP interface**, not the
implementation — they are not a debugging channel (see Security below).

## Generating a problem details response

1. **Pick the real HTTP status code first.** Generic HTTP software (caches,
   proxies, client libraries) only understands the status line.
2. **Pick the problem type URI.** Check the IANA "HTTP Problem Types" registry
   for a reusable type before minting one; read
   [references/new-problem-types.md](references/new-problem-types.md) when you
   need to define or register a new type. If the problem has no semantics
   beyond the status code, omit `type` (it defaults to `about:blank`).
3. **Populate the standard members** per the table below.
4. **Put machine-actionable specifics in extension members**, not in `detail`.
5. **Serialize with the right media type**: `Content-Type:
   application/problem+json` (or `+xml`). Returning `application/problem+json`
   even when the client did not list it in Accept is allowed by HTTP. Negotiate
   the language of human-readable strings (`title`, `detail`) with
   Accept-Language / Content-Language.
6. **Security-vet the content** (see Security below).

### Standard members

A member whose value has the wrong JSON type MUST be ignored by consumers, so
emitting the correct types matters.

| Member | JSON type | Semantics and rules |
| --- | --- | --- |
| `type` | string (URI reference) | Identifies the problem type; the type's primary identifier. Absent ⇒ `about:blank`. Absolute URIs are RECOMMENDED; a relative URI resolves against the document's base URI, so the same value yields different identities under different request paths — if relative, include the full path (e.g. `/types/123`). Non-resolvable URIs (e.g. `tag:` scheme) are allowed, but resolvable ones are encouraged: switching to a resolvable URI later creates a new identity and is a breaking change. If it is a locator, dereferencing SHOULD provide human-readable docs (e.g. HTML). |
| `status` | number | The HTTP status code the origin server generated for this occurrence. Advisory only — the generator MUST use the same code in the actual HTTP response. |
| `title` | string | Short human-readable summary of the problem **type**. SHOULD NOT change from occurrence to occurrence except for localization. With `about:blank`, title SHOULD be the recommended HTTP status phrase for the code (e.g. "Not Found" for 404), though it MAY be localized. |
| `detail` | string | Human-readable explanation of this **occurrence**. Focus on helping the client correct the problem, not on debugging information. |
| `instance` | string (URI reference) | Identifies this specific occurrence (useful for support/forensics). If dereferenceable, the problem details can be fetched from it; otherwise it is opaque to the client. Absolute URIs RECOMMENDED, same relative-URI pitfall as `type`. |

### Extension members

- Problem type definitions MAY add members specific to that type; use them for
  anything a machine should act on (balances, links, per-field errors).
- Name extensions to survive all serializations: names SHOULD start with a
  letter, SHOULD contain only ALPHA, DIGIT, and `_`, and SHOULD be at least
  three characters. (XML serialization requires conformance to the XML Name
  rule.)

### Multiple problems in one response

- Same problem type, many occurrences: design the type with an extension array
  — e.g. an `errors` array whose members carry `detail` plus a JSON `pointer`
  locating each issue in the request content.
- Problems of **different** types: it is RECOMMENDED to represent only the most
  relevant or urgent problem. Generic "batch" problem types are possible but
  map poorly onto HTTP semantics.

Read [references/examples-and-schema.md](references/examples-and-schema.md)
when you want complete request/response examples or the (non-normative) JSON
Schema to validate output.

## Defining a new problem type

Read [references/new-problem-types.md](references/new-problem-types.md)
whenever you are creating, documenting, or registering a problem type, or
deciding whether one is warranted at all.

Minimum to remember without loading it: a new problem type definition MUST
document (1) a type URI (typically http/https scheme), (2) a short title,
(3) the HTTP status code it is used with.

## Consuming problem details (client side)

- Use the `type` URI (after resolution if relative) as the problem type's
  primary identifier — consumers MUST. Missing `type` means `about:blank`:
  no semantics beyond the HTTP status code.
- MUST ignore any member whose value has the wrong JSON type (process as if
  absent).
- MUST ignore unrecognized extension members — this is what lets problem types
  evolve.
- SHOULD NOT parse `detail` for information; extensions are the reliable,
  less error-prone channel.
- SHOULD NOT automatically dereference the `type` URI, except when surfacing
  information to developers (e.g. a debugging tool).
- Treat `status` as advisory. It is useful to recover the original status when
  an intermediary or cache changed it, or when the content is persisted without
  HTTP metadata; generic HTTP software will still act on the real status line.

## Security — vet every generated problem

- Carefully vet information both when defining a type and when generating each
  occurrence: risks include leaking data that compromises the system, access to
  it, or user privacy.
- Avoid exposing implementation details such as stack dumps through the HTTP
  interface (including via links to occurrence information) — they reveal
  server internals and data.
- `status` duplicates the status line, so the two can disagree (e.g. an
  intermediary rewrote the code in transit); their relative precedence is
  undefined, and proxies, load balancers, firewalls, and virus scanners will
  not respect the member. Do not build logic that depends on them agreeing.

## Gotchas

- Wrong JSON type on a member ⇒ the member is ignored entirely, not coerced.
  A numeric-string `"status": "403"` is silently dropped by conforming clients.
- Relative `type`/`instance` URIs fragment problem identity across request
  paths — two endpoints returning `type: "example-problem"` identify two
  different problem types after resolution.
- `title` describes the type, `detail` describes the occurrence — don't put
  per-occurrence text in `title`.
- Machine-readable data belongs in extensions; clients are told not to parse
  `detail`.
- A response body's `application/problem+json` Content-Type may legitimately
  appear even though the request's Accept didn't include it.

## XML and other formats

Read [references/xml-and-other-formats.md](references/xml-and-other-formats.md)
when the API uses XML (`application/problem+xml`) or when you need to embed
problem details in HTML or another format.
