Consistent API error responses with RFC 9457 Problem Details
Every HTTP API needs an error format, and most teams invent their own. RFC 9457 defines a standard one: application/problem+json. This guide explains its members, shows validation and business-rule examples, and covers design and security rules for adopting it.
Updated 7 min read

In this article
Ask three HTTP APIs for something they cannot do and you will often get three different error shapes: one returns {"error": "Bad request"}, another returns {"message": ..., "code": 1042}, and a third returns an HTML error page with a 200 status. Every client then needs custom parsing for each API, and every new endpoint is a chance for the format to drift.
RFC 9457, "Problem Details for HTTP APIs", is the IETF's answer. Published in July 2023 on the Standards Track, it defines a small JSON (and XML) object for carrying machine-readable error details in HTTP responses, so that APIs do not have to invent their own format. It obsoletes RFC 7807, which introduced the same idea in 2016.
This guide explains the format member by member, shows realistic examples for validation and business-rule errors, and lists the design decisions and security rules you need to settle before adopting it across an API. The examples are plain HTTP and JSON, so they apply to any server language or framework.
The shape of a problem details response
A problem details object is a JSON object served with the media type application/problem+json. Here is the RFC's own example, an online store refusing a purchase because the account lacks credit:
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.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345", "/account/67890"]
}The first four members are defined by the RFC; balance and accounts are extension members defined by this particular problem type. Clients that know the type can use them; clients that do not must ignore them.
The standard members
| Member | Type | Purpose and rules from RFC 9457 |
|---|---|---|
type | URI reference | Identifies the problem type and is the primary identifier consumers MUST use. Defaults to about:blank when absent. If it is an http(s) URL, dereferencing it SHOULD give human-readable documentation, but clients SHOULD NOT fetch it automatically. |
status | Number | The HTTP status code, advisory only. Servers MUST use the same code in the actual response. |
title | String | Short human-readable summary of the problem type. SHOULD NOT change between occurrences, except for localisation. |
detail | String | Explanation specific to this occurrence, focused on helping the client fix the problem. Consumers SHOULD NOT parse it. |
instance | URI reference | Identifies this specific occurrence. May be dereferenceable, or an opaque identifier meaningful to the server. |
type is the contract
The most important design decision is the set of type URIs. Clients branch on type, not on title or detail. Use absolute HTTPS URLs under a domain you control, such as https://api.example.com/problems/insufficient-stock, and publish a short documentation page at each one. The RFC warns that relative URIs "can cause confusion" and may not be handled correctly by all implementations.
about:blank for plain HTTP errors
When an error has no meaning beyond its status code, such as a generic 404, omit type or set it to about:blank. In that case the RFC says title SHOULD be the standard reason phrase for the status code, for example "Not Found" for 404.
HTTP/1.1 404 Not Found
Content-Type: application/problem+json
{
"type": "about:blank",
"title": "Not Found",
"status": 404,
"detail": "No invoice exists with ID inv_20817."
}
Validation errors with an errors extension
Validation failures often involve several fields at once. RFC 9457 shows a pattern for this: a problem type that defines an errors extension, an array where each entry has a detail and a pointer into the request body using JSON Pointer syntax (RFC 6901).
POST /details HTTP/1.1
Host: account.example.com
Accept: application/json
{
"age": 42.3,
"profile": {
"color": "yellow"
}
}HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
Content-Language: en
{
"type": "https://example.net/validation-error",
"title": "Your request is not valid.",
"errors": [
{
"detail": "must be a positive integer",
"pointer": "#/age"
},
{
"detail": "must be 'green', 'red' or 'blue'",
"pointer": "#/profile/color"
}
]
}The pointers let a client attach each message to the right form field without parsing text. For query-string or header errors, define your own member (for example parameter or header) in the problem type's documentation.
When a request has several problems of different types, the RFC recommends returning the most relevant or urgent one rather than inventing a generic batch format.
Designing your problem types
Treat problem types like any other part of your API contract. A workable process:
- List the errors clients must handle differently. "Out of stock", "payment declined" and "version conflict" lead to different user actions; a server bug does not. Only distinct handling needs a distinct type.
- Give each a stable URI and a fixed title. The title describes the type, so it stays the same across occurrences.
- Choose the status code first, then the type. For example, RFC 9110 defines 422 (Unprocessable Content) for requests whose syntax is correct but whose instructions cannot be processed. The status code still drives generic HTTP behaviour such as caching and retries; the type refines it.
- Define extension members per type. Name them carefully: the RFC notes that names must also be valid XML names if you support the XML format. Clients must ignore unknown members, so adding a member later is backward compatible.
- Document each type at its URI: when it occurs, its status code, its extension members and what the client should do.
- Check the IANA registry first. RFC 9457 created the "HTTP Problem Types" registry for common, reusable types. Vendor- and application-specific types cannot be registered, so most of your types will live under your own domain.
A small catalogue for an ordering API might look like this:
| Type URI (suffix) | Status | Extension members | Client action |
|---|---|---|---|
/problems/validation-error | 422 | errors[] with detail and pointer | Show messages next to fields |
/problems/insufficient-stock | 409 | sku, available | Offer a lower quantity |
/problems/stale-version | 409 | currentVersion | Reload and reapply the edit |
about:blank | 404, 405, 500 and others | None | Generic handling by status |
Security rules you must not skip
Error responses are a common source of information leaks. Section 5 of RFC 9457 asks generators to scrutinise what they include, warning about details that could compromise the system, access to it or users' privacy. In practice:
- Never include stack traces, SQL, file paths or internal hostnames in
detailor extensions. The RFC specifically discourages exposing stack dumps through the HTTP interface. - Do not reveal whether a resource exists to a caller who is not allowed to see it. Return the same problem for "not found" and "not permitted" where that matters.
- Use
instanceor a request ID for correlation. Put an opaque identifier in the response and keep the full diagnostic data in your logs. - Keep
statusand the real status code identical. The RFC notes that the member duplicates the HTTP status and can disagree with it, for example when an intermediary changes the response; generic HTTP software always uses the real code. - Validate and encode on the client too. If a client shows
detailin a web page, treat it as untrusted text and escape it.

Content negotiation and adoption
Clients can signal support with Accept: application/json, application/problem+json. The RFC also defines application/problem+xml for XML APIs, and human-readable strings can be localised with Accept-Language, returning a matching Content-Language.
Problem details fit 4xx and 5xx responses most naturally, though the RFC allows them with any status. It also points out that they are not the only way to describe a problem: if the response is still a representation of a resource, a normal resource response may be the better fit.
To roll the format out across an existing API without breaking clients:
- Produce every error from one central error handler, so no endpoint builds its own error body.
- Write contract tests that assert the media type and the presence of
typeandtitlefor each documented error. - Describe the problem object once in your OpenAPI document and reference it from every error response.
- If old clients depend on legacy fields, include them temporarily as extension members, announce a removal date and remove them in the next major version.
Summary
RFC 9457 gives HTTP APIs a standard, extensible error format: type to identify the problem, title to summarise it, status to mirror the HTTP code, detail to explain this occurrence and instance to identify it, plus any extension members your types define. Adopt it by cataloguing the errors clients must handle differently, giving each a documented HTTPS type URI, centralising error generation and keeping internal details out of responses. Your clients get one parser for every error, and your API gains a contract that can grow without breaking them.
Frequently asked questions
Is RFC 7807 still valid?
RFC 9457 obsoletes RFC 7807. The core members are the same, so RFC 7807 responses remain recognisable, but new work should follow RFC 9457, which also created the IANA registry of common problem types.
Which members are required?
None is strictly required. If
typeis absent it defaults toabout:blank. In practice, always sendtypeandtitle, and includestatusanddetailwhen they help clients.Can clients parse the detail string?
They should not. The RFC says consumers SHOULD NOT parse
detail; any data a client needs belongs in an extension member defined by the problem type.What content type should the response use?
Use
application/problem+jsonfor JSON, orapplication/problem+xmlfor the XML format defined in the RFC's appendix.
Your next customer could start right here.
Introduce your tool, product or business to readers exploring technology.
Explore placements and request a private quote
Sources
- RFC 9457: Problem Details for HTTP APIs — IETF / RFC Editor
- RFC 9110: HTTP Semantics (422 Unprocessable Content) — IETF / RFC Editor
- RFC 6901: JavaScript Object Notation (JSON) Pointer — IETF / RFC Editor
- HTTP Problem Types registry — IANA, 2026-06-26
Written with substantial AI assistance. Facts checked against cited sources. Editorial policy.
Comments
No comments yet. Be the first to join the conversation.
Leave a comment
Every comment is read by a moderator before it appears. Your email address is never published; it is used only to contact you about this comment.
Related tools
- Directory profile
GitHub
Git-based platform for hosting code, reviewing pull requests, tracking issues and running CI/CD workflows, with free and per-user paid plans.
A tool connected to a service selected for this article. Compare its fit for your project; inclusion is not an endorsement.
- Directory profile
GitLab
DevSecOps platform combining Git repositories, merge request reviews, CI/CD pipelines and issue tracking, offered as SaaS, dedicated or self-managed.
A tool connected to a service selected for this article. Compare its fit for your project; inclusion is not an endorsement.
- Directory profile
Postman
API platform for designing, testing, documenting and monitoring APIs, with desktop and web apps, a CLI and a free plan.
A tool connected to a service selected for this article. Compare its fit for your project; inclusion is not an endorsement.
More from Cloudsoft Zone

Resource guideWordPress
WordPress security hardening checklist for 2026 (WordPress 7.1)
A practical WordPress 7.1 hardening checklist based on the official handbook: updates, two-step logins, wp-config.php constants, file permissions, database privileges, firewalls, WP-CLI checksum checks and tested backups.
By Cloudsoft Zone

Troubleshooting guideCodeIgniter
CodeIgniter 4 validation not working? 9 causes and fixes
Fix CodeIgniter 4 validation problems fast: wrong input source, lost errors after redirect, permit_empty, strict JSON rules, is_unique placeholders and more.
By Cloudsoft Zone

Interview preparationInterview questions
Docker interview questions and answers for Docker Engine 29
18 Docker interview questions from images and volumes to build cache, Compose, networking, signals and the containerd image store, with short model answers.
By Cloudsoft Zone
