Lesson 6 / 27

Error Responses: Problem Details

Return consistent, machine-readable errors that help the caller fix the problem.

Errors are part of the contract

Clients must handle failures, so give every error the same shape. A standard is Problem Details for HTTP APIs (RFC 9457, which replaces RFC 7807), media type application/problem+json, with members type (a URI identifying the error kind), title, status, detail and optional extensions such as an errors list for field-level validation. Make messages actionable (say what to change), use stable machine-readable type or code values that clients can switch on, include a request ID for support, and never leak internals such as stack traces, SQL or file paths.

A problem+json response, run

I ran this against a small real HTTP API built with only the Python standard library (full code in the case study). Requesting a missing item returns 404 with content type application/problem+json and the standard members.

# uses srv, base and call() from the runnable demo in the case study
s, h, b = call("GET", "/v2/items/99"); print(s, h["Content-Type"], b)

Output:

404 application/problem+json {'type': 'about:blank', 'title': 'Not Found', 'status': 404, 'detail': 'Item 99 does not exist.'}

A validation error with field details

The errors extension lists each invalid field so a UI can highlight it. (Shape from the demo API, shown as JSON.)

{
  "type": "https://api.example.com/problems/validation",
  "title": "Validation failed",
  "status": 422,
  "detail": "amount must be positive.",
  "errors": [{"field": "amount", "message": "must be > 0"}],
  "request_id": "req_8f3a21"
}

Quick check: Why give every error the same JSON shape?

  • JSON requires it
  • It hides the status code
  • It makes responses longer by design
  • Clients can handle all failures with one parser and logic
Answer

Clients can handle all failures with one parser and logic — Predictable errors reduce client code and make failures easy to log and search.