Error Response
What Are Meaningful Error Responses
A meaningful error response is a structured, consistent, and client-friendly way for a REST API to tell consumers:
- What went wrong
- Why it went wrong
- How to fix it (when appropriate)
Good error responses combine:
- Correct HTTP status codes
- Clear error identifiers (error codes)
- Human-readable messages
- Optional error details
Why Meaningful Error Responses Matter
- Better Developer Experience (DX): Clients can quickly debug and fix issues
- Fewer Support Requests: Clear errors reduce confusion
- Consistent Client Behavior: Applications can programmatically handle errors
- Security: Avoids leaking internal system details
- Scalability: Enables error tracking, logging, and monitoring
Components of a Meaningful Error Response
A well-designed error response typically includes:
{
"errorCode": "INVALID_INPUT",
"message": "Request validation failed",
"details": []
}
Component Breakdown
| Component | Purpose |
|---|---|
| HTTP Status Code | High-level error category |
| errorCode | Machine-readable identifier |
| message | Human-readable explanation |
| details | Field-level or contextual info |
HTTP Status Codes
HTTP status codes communicate the category of the error.
Commonly Used Status Codes
| Status | Meaning | When to Use |
|---|---|---|
| 400 | Bad Request | Invalid syntax or malformed input |
| 401 | Unauthorized | Missing or invalid authentication |
| 403 | Forbidden | Authenticated but not allowed |
| 404 | Not Found | Resource does not exist |
| 409 | Conflict | Resource state conflict |
| 415 | Unsupported Media Type | Wrong Content-Type |
| 422 | Unprocessable Entity | Semantic validation failure |
| 500 | Internal Server Error | Unexpected server failure |
Error Codes (Machine-Readable)
Error codes are stable, application-specific identifiers that allow clients to:
- Handle errors programmatically
- Avoid parsing human-readable text
- Support localization (i18n)
Example Error Codes
INVALID_INPUT
MISSING_REQUIRED_FIELD
AUTH_TOKEN_EXPIRED
RESOURCE_NOT_FOUND
PERMISSION_DENIED
RATE_LIMIT_EXCEEDED
Best Practices for Error Codes
- Use UPPER_SNAKE_CASE
- Keep them stable over time
- Avoid exposing internal exceptions
- Document them clearly
Error Messages (Human-Readable)
Characteristics of Good Error Messages
- Clear and concise
- Actionable when possible
- Non-technical
- Secure (no stack traces or SQL errors)
- Bad message:
"message": "NullPointerException at UserService.java:42" - Good message:
"message": "Username is required"
Field-Level Validation Errors
Example: Invalid Request Body
Request
POST /users
Content-Type: application/json
{
"username": "",
"email": "invalid-email",
"age": 15
}
Response
HTTP/1.1 422 Unprocessable Entity
Content-Type: application/json
{
"errorCode": "VALIDATION_ERROR",
"message": "One or more fields are invalid",
"details": [
{
"field": "username",
"issue": "Must not be empty"
},
{
"field": "email",
"issue": "Invalid email format"
},
{
"field": "age",
"issue": "Must be at least 18"
}
]
}
Explanation
- 422 → request syntax is valid, but semantic rules failed
- VALIDATION_ERROR → consistent error handling
- details helps client highlight specific fields
Authentication Error Example
Missing Authorization Header
Request
GET /orders
Response
HTTP/1.1 401 Unauthorized
{
"errorCode": "AUTH_REQUIRED",
"message": "Authentication token is missing or invalid"
}
Explanation
- 401 → client must authenticate
- Message clearly indicates what’s missing
- No internal auth logic exposed
Authorization Error Example
Insufficient Permissions
HTTP/1.1 403 Forbidden
{
"errorCode": "ACCESS_DENIED",
"message": "You do not have permission to access this resource"
}
Explanation
- 403 → identity is known, but access is denied
- Client should not retry with same credentials
Resource Not Found Example
Request
GET /users/9999
Response
HTTP/1.1 404 Not Found
{
"errorCode": "RESOURCE_NOT_FOUND",
"message": "User with ID 9999 was not found"
}
Explanation
- Avoids leaking whether IDs are sequential or valid
- Clear, domain-specific messaging
Conflict Error Example
Duplicate Resource Creation
POST /users
{
"email": "existing@example.com"
}
Response
HTTP/1.1 409 Conflict
{
"errorCode": "DUPLICATE_RESOURCE",
"message": "A user with this email already exists"
}
Explanation
- 409 → state conflict
- Message explains how to resolve (use another email)
Internal Server Error Example
Unexpected Failure
HTTP/1.1 500 Internal Server Error
{
"errorCode": "INTERNAL_ERROR",
"message": "An unexpected error occurred. Please try again later."
}
Explanation
- Never expose stack traces
- Detailed error logged server-side
- Generic message protects security
Consistent Error Response Format
Standard Template
{
"errorCode": "STRING",
"message": "STRING",
"details": []
}
Optional Fields
{
"timestamp": "2026-01-09T10:15:30Z",
"path": "/users",
"requestId": "abc-123"
}