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.

Soman Bandesha Updated 13 min read
REST API Error Response Format: Best Practices, Examples, and Free Checker

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

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:

  1. What type of error happened?
  2. Was this a client problem or a server problem?
  3. Which field, parameter, or resource caused it?
  4. Can the client fix it and retry?
  5. Is there a request ID that support or logs can use?
  6. 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 email and password
  • 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.

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.

FieldExampleWhy it helps
status422Matches the HTTP response status
codeVALIDATION_FAILEDGives clients a stable value for logic
message"The request body contains validation errors."Explains the issue in plain language
detailsArray of field errorsShows exactly what failed
requestIdreq_01JZ8Z9F6R7M4K2P9Q3N8V1X2AHelps trace logs
path/api/usersShows which endpoint returned the error
timestampISO timestampHelps 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:

FieldMeaning
typeA URI that identifies the problem type
titleA short summary of the problem type
statusThe HTTP status code
detailA human-readable explanation for this occurrence
instanceA 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.

OptionBest forProsTradeoff
Custom JSON formatSmall APIs, internal APIs, simple productsEasy to read and adaptYou must document your own structure
RFC 9457 Problem DetailsPublic APIs, platform APIs, larger teamsStandard-friendly and machine-readableSome 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:

  • 4xx means the client needs to change something
  • 5xx means the server failed or could not complete the request

This table covers common choices.

Status codeUse it whenExample
400The request is malformedBroken JSON
401Authentication is missing or invalidMissing bearer token
403The user is authenticated but not allowedUser lacks admin permission
404The resource cannot be foundUnknown user ID
409The request conflicts with current stateDuplicate email or version conflict
422The request is valid in shape but invalid in meaningValidation failed
429The client sent too many requestsRate limit exceeded
500The server failed unexpectedlyUnhandled exception
503The service is temporarily unavailableMaintenance 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.