Error Handling Patterns

Designing Error Responses with Problem Details (RFC 9457)

How to standardize API error responses using RFC 9457 Problem Details format — a machine-readable, human-friendly error structure.

Why Standardize Errors?

Every API team invents their own error format:

{"error": "not_found"}
{"message": "Not found", "code": 404}
{"errors": [{"field": "email", "msg": "invalid"}]}

This forces every API client to write custom error-handling code. RFC 9457 (which superseded RFC 7807) defines a standard error format that APIs, frameworks, and clients can all speak natively.

Problem Details Format

A Problem Details document is a JSON (or XML) object with five standard members:

{
  "type": "https://errors.example.com/out-of-credit",
  "title": "You do not have enough credit.",
  "status": 403,
  "detail": "Your current balance is 30, but the cost is 50.",
  "instance": "/account/12345/transactions/abc"
}

`type` — URI Reference for the Error Class

A URI that identifies the type of problem. Ideally dereferenceable — visiting the URL should return human-readable documentation about this error type. If you don't have documentation yet, use about:blank (which means the HTTP status code itself is the type).

`title` — Human-Readable Summary

A short, stable, human-readable title for the error type. This should not change between occurrences of the same error — it describes the error class, not the specific instance.

`status` — HTTP Status Code (Integer)

Mirrors the HTTP status code of the response. Including it in the body makes error handling easier for clients that might lose the status code through middleware or logging.

`detail` — Instance-Specific Explanation

Human-readable explanation of this specific occurrence of the problem. Unlike title, this should vary per occurrence.

`instance` — URI for This Occurrence

Optional. A URI that identifies the specific occurrence, often a request path or an error ID that links to a support ticket or log entry.

Extension Members

RFC 9457 explicitly allows extending the format with custom fields:

{
  "type": "https://errors.example.com/validation-error",
  "title": "Validation Failed",
  "status": 422,
  "detail": "One or more fields failed validation.",
  "errors": [
    {
      "field": "email",
      "message": "Must be a valid email address",
      "value": "not-an-email"
    }
  ]
}

The errors array is an extension member — custom to your API but still within the Problem Details envelope.

Content-Type

Always use the Problem Details media type:

Content-Type: application/problem+json

This lets clients distinguish error responses from success responses based on content type alone.

Examples by Status Code

400 Bad Request

{
  "type": "https://errors.example.com/malformed-request",
  "title": "Malformed Request Body",
  "status": 400,
  "detail": "Request body could not be parsed as JSON."
}

404 Not Found

{
  "type": "about:blank",
  "title": "Not Found",
  "status": 404,
  "detail": "Product with ID 9999 does not exist.",
  "instance": "/products/9999"
}

429 Too Many Requests

{
  "type": "https://errors.example.com/rate-limit-exceeded",
  "title": "Rate Limit Exceeded",
  "status": 429,
  "detail": "You have exceeded 100 requests per minute.",
  "retry_after": 47
}

Framework Implementation

Django REST Framework

from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status

def problem_details_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if response is not None:
        response.data = {
            "type": "about:blank",
            "title": str(exc),
            "status": response.status_code,
            "detail": response.data.get("detail", ""),
        }
        response["Content-Type"] = "application/problem+json"
    return response

Summary

RFC 9457 Problem Details gives your API a standard, machine-readable error format. Use application/problem+json as the content type, include type, title, status, and detail in every error, and add extension members for validation errors. Clients can then handle errors generically rather than parsing ad-hoc formats.

Related Protocols

Related Glossary Terms

More in Error Handling Patterns