REST API Error Response Format: Best Practices, Examples, and Free Checker
Learn the best REST API error response format with JSON examples, HTTP status code guidance, RFC 9457 notes, and a free checker to validate your API error body.
REST API error response format: best practices, examples, and free checker
A good REST API error response format should do one thing well: tell the developer what went wrong and what to fix next.
That sounds simple, but a lot of APIs still return errors like this:
{
"error": "Something went wrong"
}
That message is almost useless. The client does not know whether the problem is bad JSON, a missing field, an expired token, a permission issue, a duplicate record, or a server bug.
A better API error response gives the client a clear HTTP status code, a stable error code, a readable message, and enough detail to debug the request safely.
You can paste your own JSON into the REST API Error Response Checker to see whether your error body is consistent, readable, and standard-friendly.
Table of contents
- What a REST API error response should do
- Bad vs good API error responses
- Recommended REST API error response format
- RFC 9457 Problem Details format
- Common REST API error response examples
- Which HTTP status code should you use?
- Common API error response mistakes
- How to check your API error response format
- FAQ
What a REST API error response should do
An API error response is part of your developer experience.
When someone integrates with your API, they will hit errors. That is normal. Maybe they forgot a required field. Maybe their token expired. Maybe they passed a valid JSON body with invalid business data. Maybe your server failed.
The error response should help them recover without guessing.
A useful API error response should answer these questions:
- What type of error happened?
- Was this a client problem or a server problem?
- Which field, parameter, or resource caused it?
- Can the client fix it and retry?
- Is there a request ID that support or logs can use?
- Is the format predictable across the whole API?
The last point matters more than people think. If one endpoint returns message, another returns error, and another returns errors, client code becomes messy fast.
Consistency is the real win.
Bad vs good API error responses
Bad API errors are short, vague, and hard to act on.
{
"error": "Invalid request"
}
This tells the client almost nothing. Which part of the request is invalid? Is the JSON malformed? Is a field missing? Is a value outside the allowed range?
A better response gives more context.
{
"status": 422,
"code": "VALIDATION_FAILED",
"message": "The request body contains validation errors.",
"details": [
{
"field": "email",
"issue": "Email address is not valid."
},
{
"field": "password",
"issue": "Password must be at least 12 characters."
}
],
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A",
"path": "/api/users"
}
This is easier to debug because the client can see:
- The HTTP status is
422 - The internal error code is
VALIDATION_FAILED - The issue is validation, not authentication or server failure
- The broken fields are
emailandpassword - The request ID can be used for logs or support
You do not need this exact structure for every API. But you do need a structure that stays consistent.
Recommended REST API error response format
For many APIs, this format is practical:
{
"status": 422,
"code": "VALIDATION_FAILED",
"message": "The request body contains validation errors.",
"details": [
{
"field": "email",
"issue": "Email address is not valid."
}
],
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A",
"path": "/api/users",
"timestamp": "2026-06-11T10:15:30Z"
}
Each field has a job.
| Field | Example | Why it helps |
|---|---|---|
status | 422 | Matches the HTTP response status |
code | VALIDATION_FAILED | Gives clients a stable value for logic |
message | "The request body contains validation errors." | Explains the issue in plain language |
details | Array of field errors | Shows exactly what failed |
requestId | req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A | Helps trace logs |
path | /api/users | Shows which endpoint returned the error |
timestamp | ISO timestamp | Helps debugging across logs and systems |
You can add more fields if your API needs them, but do not turn every error into a giant object. Most clients need clarity, not a dump of internal state.
Use stable error codes
HTTP status codes are useful, but they are not enough.
For example, a 422 response can mean many different things:
- Invalid email
- Missing required field
- Unsupported enum value
- Date range conflict
- Quantity below minimum
- File too large
That is why a stable application-level error code helps.
{
"status": 422,
"code": "EMAIL_ALREADY_EXISTS",
"message": "An account with this email already exists.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
Clients can safely build logic around EMAIL_ALREADY_EXISTS. They should not parse the human-readable message string.
A good rule:
Use code for machines. Use message for humans.
Write error messages developers can act on
An API error message should be specific, but not risky.
Bad:
{
"message": "Failed"
}
Better:
{
"message": "The email field is required."
}
Even better:
{
"status": 422,
"code": "REQUIRED_FIELD_MISSING",
"message": "The email field is required.",
"details": [
{
"field": "email",
"issue": "This field is required."
}
]
}
Do not expose stack traces, database errors, file paths, secret names, SQL queries, or private infrastructure details.
Bad:
{
"status": 500,
"message": "SQLSTATE[23000]: Integrity constraint violation in /var/www/app/UserRepository.php on line 87"
}
Better:
{
"status": 500,
"code": "INTERNAL_SERVER_ERROR",
"message": "The server could not complete the request.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
Log the stack trace on your side. Give the client the request ID.
RFC 9457 Problem Details format
If you want a standard format, look at RFC 9457, also known as Problem Details for HTTP APIs.
RFC 9457 defines a common way to return machine-readable error details in HTTP API responses. It also obsoletes RFC 7807.
The common media type is:
Content-Type: application/problem+json
A basic RFC 9457 style response looks like this:
{
"type": "https://api.example.com/problems/validation-error",
"title": "Validation failed",
"status": 422,
"detail": "The request body contains one or more invalid fields.",
"instance": "/api/users/requests/req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
The standard fields are:
| Field | Meaning |
|---|---|
type | A URI that identifies the problem type |
title | A short summary of the problem type |
status | The HTTP status code |
detail | A human-readable explanation for this occurrence |
instance | A URI reference for this specific error occurrence |
You can also add extension fields when your API needs more detail.
{
"type": "https://api.example.com/problems/validation-error",
"title": "Validation failed",
"status": 422,
"detail": "The request body contains one or more invalid fields.",
"instance": "/api/users/requests/req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A",
"errors": [
{
"field": "email",
"message": "Email address is not valid."
}
],
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
This gives you a standard base without losing practical field-level errors.
Simple custom format vs RFC 9457
Both options can work. The right choice depends on your API and your users.
| Option | Best for | Pros | Tradeoff |
|---|---|---|---|
| Custom JSON format | Small APIs, internal APIs, simple products | Easy to read and adapt | You must document your own structure |
| RFC 9457 Problem Details | Public APIs, platform APIs, larger teams | Standard-friendly and machine-readable | Some teams need time to learn the format |
If you already have a simple, consistent error format, you do not need to rewrite everything tomorrow. But if you are building a new public API, RFC 9457 is a clean default.
Common REST API error response examples
400 Bad Request
Use 400 when the request is malformed or the server cannot understand it.
Example: invalid JSON.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"status": 400,
"code": "MALFORMED_JSON",
"message": "The request body contains invalid JSON.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A",
"path": "/api/users"
}
401 Unauthorized
Use 401 when authentication is missing or invalid.
{
"status": 401,
"code": "AUTHENTICATION_REQUIRED",
"message": "A valid access token is required.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
For many APIs, this should also include a WWW-Authenticate header when applicable.
403 Forbidden
Use 403 when the client is authenticated but does not have permission.
{
"status": 403,
"code": "INSUFFICIENT_PERMISSIONS",
"message": "You do not have permission to access this resource.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
404 Not Found
Use 404 when the resource does not exist or should not be revealed to the client.
{
"status": 404,
"code": "USER_NOT_FOUND",
"message": "No user was found for the provided identifier.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A",
"path": "/api/users/123"
}
Be careful with sensitive resources. Sometimes 404 is safer than telling the client that a private resource exists.
409 Conflict
Use 409 when the request conflicts with the current state of the resource.
{
"status": 409,
"code": "RESOURCE_CONFLICT",
"message": "The email address is already used by another account.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
Common examples:
- Duplicate email
- Version mismatch
- Resource already exists
- State transition is not allowed
422 Unprocessable Content
Use 422 when the request syntax is valid, but the server cannot process the instructions.
{
"status": 422,
"code": "VALIDATION_FAILED",
"message": "The request body contains validation errors.",
"details": [
{
"field": "quantity",
"issue": "Quantity must be greater than zero."
}
],
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
This is common for validation errors where the JSON is valid, but the data does not pass business rules.
500 Internal Server Error
Use 500 when something failed on the server and the client cannot fix it.
{
"status": 500,
"code": "INTERNAL_SERVER_ERROR",
"message": "The server could not complete the request.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
Do not send raw exception messages to the client. Use logs for that.
Which HTTP status code should you use?
HTTP status codes are grouped by class. For API errors, the main split is simple:
4xxmeans the client needs to change something5xxmeans the server failed or could not complete the request
This table covers common choices.
| Status code | Use it when | Example |
|---|---|---|
400 | The request is malformed | Broken JSON |
401 | Authentication is missing or invalid | Missing bearer token |
403 | The user is authenticated but not allowed | User lacks admin permission |
404 | The resource cannot be found | Unknown user ID |
409 | The request conflicts with current state | Duplicate email or version conflict |
422 | The request is valid in shape but invalid in meaning | Validation failed |
429 | The client sent too many requests | Rate limit exceeded |
500 | The server failed unexpectedly | Unhandled exception |
503 | The service is temporarily unavailable | Maintenance or overload |
The error body should not contradict the HTTP status.
Bad:
HTTP/1.1 200 OK
{
"success": false,
"error": "Payment failed"
}
Better:
HTTP/1.1 402 Payment Required
{
"status": 402,
"code": "PAYMENT_FAILED",
"message": "The payment could not be processed.",
"requestId": "req_01JZ8Z9F6R7M4K2P9Q3N8V1X2A"
}
If the operation failed, do not hide that failure inside a 200 OK response.
Common API error response mistakes
Returning different formats from different endpoints
This is one of the most common problems.
Endpoint A:
{
"error": "Invalid email"
}
Endpoint B:
{
"message": "User not found"
}
Endpoint C:
{
"errors": [
"Password is too short"
]
}
Pick one format and use it everywhere.
Using only human-readable messages
Human-readable messages are good for debugging, but clients should not build logic around them.
Bad client logic:
if (error.message === "Email already exists") {
showLoginLink();
}
Better client logic:
if (error.code === "EMAIL_ALREADY_EXISTS") {
showLoginLink();
}
Messages change. Error codes should be stable.
Exposing private server details
Never expose raw stack traces, SQL errors, internal service names, or secret values in API responses.
The client needs a useful message and a request ID. Your logs need the internal details.
Returning 500 for everything
A validation error is not a 500. A missing token is not a 500. A duplicate email is usually not a 500.
If the client can fix the request, use a 4xx status. Save 5xx for server failures.
Making validation errors hard to parse
Validation errors should show the exact field and issue.
Bad:
{
"message": "Invalid fields"
}
Better:
{
"status": 422,
"code": "VALIDATION_FAILED",
"message": "The request body contains validation errors.",
"details": [
{
"field": "email",
"issue": "Email address is not valid."
},
{
"field": "age",
"issue": "Age must be 18 or older."
}
]
}
This helps frontend teams show field-level messages without guessing.
Document your API errors
Good error responses still need documentation.
If your API has docs, include:
- Common HTTP status codes for each endpoint
- Example error response bodies
- Stable error code list
- Validation error structure
- Authentication and permission errors
- Rate limit behavior
- Request ID behavior
- Whether you use RFC 9457 or a custom format
If you use OpenAPI, document error responses in your OpenAPI file.
Example:
responses:
"422":
description: Validation failed
content:
application/json:
schema:
type: object
properties:
status:
type: integer
example: 422
code:
type: string
example: VALIDATION_FAILED
message:
type: string
example: The request body contains validation errors.
details:
type: array
items:
type: object
properties:
field:
type: string
example: email
issue:
type: string
example: Email address is not valid.
API docs are not just for humans. They also help SDK generators, testing tools, QA teams, and support teams.
How to check your API error response format
You can review an API error response manually, but a checker is faster.
Use the REST API Error Response Checker when you want to test whether your JSON has a clean structure.
A good checker should help you catch issues like:
- Missing
status - Status code does not match the error body
- Missing readable message
- Missing stable error code
- Vague error messages
- Weak validation error details
- Missing request ID
- Mixed naming patterns
- RFC 9457 fields used incorrectly
- Server details exposed by mistake
Paste an error response, review the feedback, then fix the response before you publish it in your API docs.
Practical checklist
Before you ship an API error response, check these items:
- The HTTP status code matches the failure
- The body includes a clear message
- The body includes a stable error code
- Validation errors identify the field and issue
- The response includes a request ID
- The response does not leak stack traces or database errors
- The same format is used across endpoints
- The format is documented
- Public APIs consider RFC 9457
- Error examples are included in API documentation
If you cannot explain an error response to another developer in 30 seconds, the format probably needs work.
FAQ
What is the best REST API error response format?
The best REST API error response format is consistent, readable, and easy for client code to parse. A practical format includes status, code, message, optional details, requestId, and path. Public APIs should also consider RFC 9457 Problem Details.
Should API errors use RFC 9457?
Use RFC 9457 if you want a standard problem detail format for HTTP API errors. It is a strong choice for public APIs, platform APIs, and teams that want a machine-readable structure based on a published standard.
What should an API error message include?
An API error message should explain what went wrong in plain language. It should not expose stack traces, SQL errors, server file paths, or secrets. Use a stable code field for client logic and a readable message for developers.
What is the difference between 400 and 422?
Use 400 Bad Request when the request is malformed or cannot be understood. Use 422 Unprocessable Content when the request syntax is valid, but the data fails validation or business rules.
Should REST APIs return 200 with an error body?
No. If the request failed, return an error status code. A 200 OK response with "success": false makes client logic harder and hides useful HTTP semantics.
Should every API error include a request ID?
Yes, for most production APIs. A request ID helps developers, support teams, and backend engineers trace the error in logs without exposing private server details to the client.
Final thoughts
API errors are not edge cases. They are part of the product.
A clean REST API error response format makes your API easier to debug, easier to document, and easier to integrate with. Start with a consistent JSON structure. Use the right HTTP status code. Add stable error codes. Keep messages useful. Do not leak internals.
Then test real examples with the REST API Error Response Checker before they end up in production or public docs.