Skip to content
‹ All posts
  • API design
  • developer guide
  • API reliability
  • web engineering

Clear API Error Responses: Status Codes, Problem Details and Safe Messages

, by System Admin

Illustration of an API response protected by a shield

A useful API error tells a caller what happened and what they can do next. Vague responses make integrations harder to debug, while overly detailed ones can expose internal or sensitive information. A consistent format helps developers handle failures without guessing.

Keep the HTTP status meaningful

Use the HTTP status code to communicate the broad outcome: for example, whether the request was invalid, authentication is required, access is forbidden, a resource was not found, or the server encountered an unexpected problem. Do not return 200 OK for a failed operation and expect clients to infer failure from a field in the response body.

Keep the body consistent with the actual HTTP response. Generic HTTP software may rely on the status line without understanding your JSON format.

Use a standard structure

RFC 9457 defines a standard problem-details format for HTTP APIs. Its JSON representation uses the application/problem+json media type and supports fields such as:

  • type: a URI identifying the problem type.
  • title: a short summary of that problem type, generally stable across occurrences.
  • status: the HTTP status code generated for this occurrence; the actual response status must agree.
  • detail: a human-readable explanation specific to this occurrence, focused on helping the client correct the problem rather than debugging the server.
  • instance: a URI identifying this particular occurrence, if useful.

For example, a validation failure might use a stable problem type such as https://api.example.com/problems/invalid-input and explain: “The email field must contain a valid address.” Document any extension fields you add, such as field-level validation errors. Clients should branch on documented machine-readable fields, not parse the wording of detail.

Make errors useful, not leaky

Explain the problem in terms the caller can act on. For invalid input, identify the field and expected correction. For an expired credential, say authentication needs to be renewed. For a temporary service issue, make clear that the request did not succeed and whether a retry may be reasonable.

Do not return stack traces, SQL fragments, internal hostnames, secrets, or raw exception messages to clients. Keep diagnostic details in access-controlled server logs, and provide a safe occurrence identifier that a caller can include when contacting support. Avoid placing personal or confidential data in error text or identifiers.

This follows the OWASP REST Security guidance: return generic client-facing errors where appropriate, and do not expose technical details such as call stacks or internal hints.

Keep the contract predictable

Document problem types, status codes, and extension fields. Give clients stable machine-readable identifiers to handle; do not ask them to interpret human wording. Treat changes to the response shape or meaning as API contract changes, and test that the body and actual HTTP status agree.

Make failures observable too. Track counts by status and problem type, and log enough context to diagnose them without recording credentials or sensitive request bodies.

Practical checklist

  • Choose an HTTP status that accurately describes the result.
  • Use one documented response format, such as RFC 9457 problem details.
  • Keep the body’s status, when present, aligned with the HTTP response.
  • Provide stable problem identifiers and concise, actionable explanations.
  • Keep internal diagnostics and sensitive data out of client responses.
  • Document extension fields and test the error contract.

Further reading