Currently Available: Need a skilled Software Developer for your next project?
Categories
APIs

How to Return Structured API Errors with RFC 9457 Problem Details

When an HTTP API returns an error, its status code tells the client the general result, but not always what went wrong or what to do next. RFC 9457 Problem Details defines a standard format for including error details in an HTTP response that software can read. It replaces RFC 7807.

Return the HTTP status code that matches the error, then include a JSON problem details object using the media type application/problem+json. The object gives clients a consistent way to identify the error and show an explanation. Clients can then handle known errors without parsing custom response formats or relying on specific wording.

Put the problem details object in the response body

A problem details response uses the usual HTTP status line and headers, with a structured body. For example:

HTTP/1.1 400 Bad Request
Content-Type: application/problem+json
{
  "type": "about:blank",
  "title": "Bad Request",
  "status": 400,
  "detail": "The request could not be processed."
}

The standard defines five core members. An API can omit members that do not apply:

Member Purpose
type A URI reference that identifies the category of problem. If omitted, it defaults to about:blank.
title A short summary of the problem type. For about:blank, use the standard phrase for the HTTP status.
status The HTTP status code the server generated for this occurrence.
detail A human-readable explanation of this particular occurrence.
instance A URI reference that identifies this particular occurrence.

The HTTP response status remains authoritative. Set the body’s status member to the same code. An intermediary or client uses the HTTP status, not the value in the body. The RFC 9457 specification defines JSON and XML formats: application/problem+json and application/problem+xml. JSON is the common choice for JSON APIs.

Choose the status before defining the problem type

Set the HTTP status to match what happened before you write the body. Clients, proxies, caches, and retry libraries often act on the status without reading the JSON. The body adds context, but clients still need an accurate HTTP status; it cannot correct a misleading status code.

Use type to identify a meaningful category of error, such as a particular validation failure or a conflict with the current resource state. A specific type lets clients recognize the error and take a defined action. If every error uses about:blank or a type that only repeats the status code, clients cannot distinguish between error categories.

Treat the type identifier as part of the API contract. Keep it stable and document its meaning. Keep title short, and use detail to explain this particular error. Clients should choose what to do based on stable identifiers such as type, not by parsing detail, because its wording can change or be translated.

For security-sensitive requests, 401 indicates that the request lacks valid authentication credentials, while 403 means the server refuses it. Returning 403 to someone who is not authenticated can reveal that a protected resource exists, so follow the API’s authentication rules and account for what the response reveals. For rate limiting, return 429 and include a Retry-After header so clients know when to try again. These status-code practices are described in API error-handling guidance.

Add extensions for details clients need

Add custom fields, called extension members, when clients need structured information beyond the standard fields. For example, a validation response can give clients an error for each field, so they can connect each problem to an input. Define the field names and meanings in the API contract, and keep them stable. RFC 9457 allows extensions and requires clients to ignore extension members they do not recognize.

Keep text for people separate from instructions that software can act on. A client should not decide what to do by searching for a phrase in detail. It should use the problem type or a documented extension instead. If the API localizes human-readable strings, it can use the Accept-Language request header to select a language.

One problem details object describes one type of problem. If a request has several validation failures of that type, an extension can list the errors for each field. If the response involves different problem types, RFC 9457 recommends returning the most relevant or urgent problem, rather than using the object to list unrelated failures.

Keep every error path consistent and safe

Use the same response format for errors from request handlers, framework exception handlers, and gateways that generate API responses. If the formats differ, clients must build and maintain separate parsers for each kind of failure.

Frameworks can handle much of the response formatting. Spring Framework provides ProblemDetail and related error-response support. In Spring Boot, setting spring.mvc.problemdetails.enabled to true enables problem details handling for built-in exceptions. ASP.NET Core offers AddProblemDetails and exception-handling middleware, code that handles exceptions, to produce problem details responses. Before relying on defaults, check how your framework version and configuration handle custom exceptions and empty error responses. See the Spring Framework error-response documentation and ASP.NET Core implementation guidance.

Keep internal diagnostic information out of responses. Do not return stack traces, SQL statements, secrets, internal hostnames or details that reveal whether a user account exists. Log diagnostic information on the server, and return only information the API intends clients to use.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *