RFC 9457: A Standard Shape for HTTP API Errors

May 10, 2026

Every HTTP API eventually invents its own error shape. One service returns { "error": "..." }, the next returns { "code": 42, "message": "..." }, the third puts everything in the status text. Clients end up writing per-service adapters for what should be the most boring part of an API.

RFC 9457 — Problem Details for HTTP APIs is the IETF's answer to this. It was published in July 2023 and obsoletes RFC 7807 (March 2016). The two are intentionally backward-compatible — if you already speak 7807, you already speak 9457.

What the spec actually defines

A small JSON object served under the media type application/problem+json (or application/problem+xml for the XML serialization). The five standard members are:

FieldRequiredWhat it is
typeno*A URI identifying the problem type. Should ideally dereference to human-readable docs. Defaults to "about:blank".
titleno*A short, human-readable summary of the problem type. Shouldn't change per occurrence.
statusnoThe HTTP status code, duplicated in the body so it survives proxies that rewrite responses.
detailnoA human-readable explanation specific to this occurrence.
instancenoA URI identifying the specific occurrence (often the failing request path).

*Technically all members are optional, but consumers are told to treat type as the primary identifier and to fall back to title when they don't recognize the URI.

You're also allowed — and encouraged — to add extension members for whatever your domain needs. Unknown extensions must be ignored by clients, so adding a trace_id or balance field doesn't break anyone.

A canonical example, lifted from the RFC itself:

HTTP/1.1 403 Forbidden Content-Type: application/problem+json Content-Language: en { "type": "https://example.com/probs/out-of-credit", "title": "You do not have enough credit.", "status": 403, "detail": "Your current balance is 30, but that costs 50.", "instance": "/account/12345/msgs/abc", "balance": 30, "accounts": ["/account/12345", "/account/67890"] }

balance and accounts are extension members. A client that doesn't know about them just ignores them; one that does can use them to render a useful error UI without a second round-trip.

What 9457 changed from 7807

Three things, all in Appendix D:

  1. A problem type registry. Section 4.2 introduces an IANA registry of common problem type URIs so multiple APIs can converge on the same type for the same situation instead of each minting their own.
  2. Clearer guidance for multiple problems. 7807 left a door open to returning a list of unrelated problems (and the 207 Multi-Status pattern that often came with it). 9457 closes that door — a problem details response should describe one problem. Related sub-errors (like field-level validation failures) still belong in an extension array — typically called errors — but they should share a single overall type.
  3. Non-dereferenceable type URIs. Section 3.1.1 explicitly OKs schemes like tag: for cases where you don't want to (or can't) host docs at the URL.

In practice, the most common payload that came out of these changes is the validation-error shape:

{ "type": "https://example.net/validation-error", "title": "Your request is invalid.", "status": 422, "errors": [ { "detail": "must be a positive integer", "pointer": "#/age" }, { "detail": "must be 'green', 'red' or 'blue'", "pointer": "#/profile/color" } ] }

One overall problem (validation-error), several field-level details, each pointing at the offending location with a JSON Pointer. That's the 9457-blessed pattern.

Drop-in implementations

You don't have to hand-roll this. The Node ecosystem alone has at least two well-maintained options worth knowing about.

For NestJS, nest-problem-details-filter, by Abdeldjalil Fortas, wires an exception filter that converts every HttpException into an application/problem+json response — no controller changes required.

// main.ts import { HttpAdapterHost } from '@nestjs/core'; import { HttpExceptionFilter } from 'nest-problem-details-filter'; app.useGlobalFilters( new HttpExceptionFilter(app.get(HttpAdapterHost)), );

You keep throwing BadRequestException, NotFoundException, etc., and clients start seeing well-formed Problem Details on the wire. It also handles the Retry-After header per RFC 9110 (for 429/503), ships an optional Swagger decorator, and supports both the Express and Fastify adapters.

For Hono — and by extension anything running on the edge (Cloudflare Workers, Deno, Bun, Node) — hono-problem-details, by Ryota Ikezawa, registers as the global error handler:

import { problemDetailsHandler } from 'hono-problem-details'; app.onError(problemDetailsHandler());

It has zero runtime dependencies beyond Hono itself, plugs into Zod / Valibot / Standard Schema to produce the validation-error shape above, and ships a typed problem registry so you can define your domain error types once and get compile-time checks at every throw site.

For Python, rfc9457 — published under the NRWLDev org by Daniel Edgecombe, lead engineer at Narwhal Engineering — is the core exception library. You subclass a base problem class, set a title, raise it from your endpoint, and call .marshal() to get the RFC-shaped dict. For FastAPI specifically, the companion fastapi-problem package wires that into an exception handler so you don't have to:

from fastapi import FastAPI from fastapi_problem.handler import new_exception_handler, add_exception_handler from rfc9457 import NotFoundProblem class UserNotFoundError(NotFoundProblem): title = "User not found." app = FastAPI() add_exception_handler(app, new_exception_handler()) @app.get("/users/{user_id}") async def get_user(user_id: str): raise UserNotFoundError(detail=f"No user with id {user_id}.")

If you'd rather skip the third-party-package question entirely, Litestar (Python's high-performance ASGI framework) ships first-party RFC 9457 support via its built-in ProblemDetailsPlugin. Register it on the app and flip one config flag to auto-convert every HTTPException into a Problem Details response:

from litestar import Litestar from litestar.plugins.problem_details import ProblemDetailsPlugin, ProblemDetailsConfig app = Litestar( plugins=[ ProblemDetailsPlugin( ProblemDetailsConfig(enable_for_all_http_exceptions=True), ), ], )

You can also pass an exception_to_problem_detail_map to wire your own domain exceptions into the same response shape.

Other major frameworks have first-party support too: Spring Boot ships ProblemDetail natively since 6.x, and ASP.NET has ProblemDetails baked into the controller pipeline. Whichever you pick, the bytes on the wire come out the same shape.

If you'd rather work at the library layer than the framework layer, there's also a framework-agnostic error catalog in early development: JohnAdib/rfc9457, by John Adib, ships 39 prebuilt errors with semantic aliases (errors.client.idNotFound(), errors.server.db(), and so on) and zero runtime dependencies. You construct the error object and still wire the HTTP response yourself outside of its built-in Hono middleware. Worth knowing about, but it's new enough (single-digit stars at the time of writing) that I'd kick the tires before betting on it.

If you're on standalone Fastify specifically, there's also an early-stage fastify-rfc9457 plugin by Francesco Capurso that wires the Problem Details format into Fastify's reply pipeline and ships built-in i18n for error messages (EN/IT/ES/DE/FR) — same nascent-project caveat applies.

Connect with the maintainers

The libraries above are open-source efforts maintained by individual engineers. If you find any of them useful in your stack, the people behind them are worth following.

Abdeldjalil Fortas
Abdeldjalil FortasSoftware Engineer at Deutsche Bank, based in Berlin — maintains nest-problem-details-filter, the NestJS exception filter for Problem Details.
Ryota Ikezawa
Ryota IkezawaSenior software engineer — maintains hono-problem-details, the Hono middleware for Problem Details.
Daniel Edgecombe
Daniel EdgecombeLead Engineer at Narwhal Engineering (NRWLDev) — maintains rfc9457, fastapi-problem, starlette-problem.
John Adib
John AdibSoftware engineer in London — maintains the framework-agnostic rfc9457 TypeScript error catalog.
Francesco Capurso
Francesco CapursoMaintains fastify-rfc9457, a Fastify plugin for Problem Details with built-in error-message i18n.

Worth adopting?

Probably yes, mostly because the alternative is doing the same design work yourself for worse interop. You were going to invent some error shape regardless. Picking 9457 means the shape is documented, the libraries exist, and anyone who's hit another 9457 API already knows how to parse it. A few hours wiring up a filter (or a middleware, or whatever your framework calls it) buys you the rest for free.

Links

rfc-editor.org
RFC 9457: Problem Details for HTTP APIs | RFC Editor
This document defines a "problem detail" to carry machine-readable details of errors in HTTP response content to avoid the need to define new error response formats for HTTP APIs. This document obsoletes RFC 7807.
rfc-editor.org
RFC 7807: Problem Details for HTTP APIs | RFC Editor
This document defines a "problem detail" as a way to carry machine- readable details of errors in a HTTP response to avoid the need to define new error response formats for HTTP APIs.
GitHub
GitHub - Fcmam5/nest-problem-details: A Nest.js HTTP exceptions filter returning RFC 9457 / RFC-7807 responses
A Nest.js HTTP exceptions filter returning RFC 9457 / RFC-7807 responses - Fcmam5/nest-problem-details
GitHub
GitHub - paveg/hono-problem-details: RFC 9457 Problem Details middleware for Hono
RFC 9457 Problem Details middleware for Hono. Contribute to paveg/hono-problem-details development by creating an account on GitHub.
GitHub
GitHub - NRWLDev/rfc9457: Implementation of RFC9457 problem exception class
Implementation of RFC9457 problem exception class. Contribute to NRWLDev/rfc9457 development by creating an account on GitHub.
PyPI
rfc9457
Implementation of RFC9457 problems.
PyPI
fastapi-problem
FastAPI support for RFC9457 problems.
GitHub
GitHub - litestar-org/litestar: Light, flexible and extensible ASGI framework | Built to scale
Light, flexible and extensible ASGI framework | Built to scale - litestar-org/litestar
GitHub
GitHub - JohnAdib/RFC9457: TypeScript-first RFC 9457 compliant HTTP error handling for Node.js. Zero dependencies, fully typed, framework-agnostic.
TypeScript-first RFC 9457 compliant HTTP error handling for Node.js. Zero dependencies, fully typed, framework-agnostic. - JohnAdib/RFC9457
GitHub
GitHub - fracabu/fastify-rfc9457: A Fastify plugin for standardized, RFC 9457 compliant error responses (Problem Details) in HTTP APIs.
A Fastify plugin for standardized, RFC 9457 compliant error responses (Problem Details) in HTTP APIs. - fracabu/fastify-rfc9457

Comments

GitHub
LinkedIn