Skip to content

Structuring REST API Error Responses

Well-structured error responses are essential for building reliable APIs. They enable developers to:

  • Handle errors consistently across all endpoints,
  • Debug issues faster with clear, actionable information,
  • Build stable client applications that gracefully handle failures,
  • Reduce support burden by providing self-explanatory error messages.

When errors are structured predictably, both humans and systems can quickly understand what went wrong and how to fix it.


Use the appropriate HTTP status code for the error. This helps clients quickly understand the type of issue:

  • 4xx: Client-related errors (e.g., invalid input, not found).
  • 5xx: Server-related errors (e.g., internal server issues).

Common status codes:

  • 400 Bad Request: Invalid or missing parameters.
  • 401 Unauthorized: Authentication failure.
  • 403 Forbidden: Authentication succeeded, but the user doesn’t have permission.
  • 404 Not Found: Resource is not found.
  • 422 Unprocessable Entity: Request is well-formed but contains validation errors.
  • 500 Internal Server Error: Server encountered an unexpected condition.

To properly structure a REST API response with an error message, you should follow a standard format that makes the response easy to understand and consistent.


Keep the error response format consistent with your successful responses (e.g., JSON), so clients can parse it uniformly.

A well-structured error response typically includes:

  • status: Indicates the outcome (e.g., "error" or "fail").
  • message: A concise, human-readable description of the error.
  • details (optional): Additional context, such as validation errors or specific fields that failed.
  • documentation_url (optional): A link to relevant API documentation for the error.
  • error_id (optional): A unique identifier for server errors, useful for debugging and support requests.

Example 1: Validation Error (400 Bad Request)

Section titled “Example 1: Validation Error (400 Bad Request)”

Here’s a sample response for when required parameters are missing or invalid:

{
"status": "error",
"message": "Validation failed: Missing required fields",
"details": [
{
"field": "email",
"issue": "This field is required"
},
{
"field": "password",
"issue": "Must be at least 8 characters long"
}
],
"documentation_url": "https://api.example.com/docs/errors#validation"
}

For when a requested resource doesn’t exist:

{
"status": "error",
"message": "User not found",
"details": {
"resource_type": "user",
"resource_id": "12345"
},
"documentation_url": "https://api.example.com/docs/errors#not-found"
}

For internal server errors (avoid exposing sensitive details):

{
"status": "error",
"message": "An unexpected error occurred. Please try again later.",
"error_id": "req_abc123def456",
"documentation_url": "https://api.example.com/docs/errors#server-error"
}

  1. Match HTTP status to error type: Use 4xx for client errors, 5xx for server errors.
  2. Use consistent field names: Stick to the same field names across all error responses (e.g., always use message, not sometimes error or description).
  3. Include error tracking: For server errors, include an error_id to help with debugging and support requests.
  4. Provide field-level feedback: For validation errors, include specific details about which fields failed and why, so users can correct their input.

  • Slim HTTP Exceptions for using framework-level exceptions that map to HTTP status codes.
  • Custom Error Handler for implementing a centralized error handler that formats these responses automatically.