Handling Error Responses
| Format | Specification |
| RFC 7807 | Problem Details for HTTP APIs |
| JSON:API errors | jsonapi.org/format/#errors |
| Google API Error | { error: { code, message, status } } |
| GraphQL errors | errors[] in body |
2. Setting Custom Error Messages
Example: Friendly error template
{
"type": "https://errors.example.com/insufficient-funds",
"title": "Insufficient Funds",
"status": 402,
"detail": "Account balance $5.00 is less than required $25.00",
"instance": "/v1/payments/p_abc123",
"balance": 5.00,
"required": 25.00,
"request_id": "req_xyz789"
}
3. Implementing Error Code Mapping
| Status | Meaning | Retry? |
| 400 | Bad Request | No (fix req) |
| 401 | Unauthenticated | After re-auth |
| 403 | Forbidden | No |
| 404 | Not Found | No |
| 409 | Conflict | Maybe |
| 422 | Unprocessable Entity | No |
| 429 | Too Many Requests | Yes (backoff) |
| 500 | Server Error | Yes |
| 502/503/504 | Gateway/Upstream | Yes |
4. Using Error Response Templates
Example: NGINX custom error pages
error_page 404 /errors/404.json;
error_page 502 503 504 /errors/upstream.json;
location ~ ^/errors/ { internal; root /etc/nginx; }
5. Configuring Detailed vs Generic Errors
| Environment | Detail Level |
| Production | Generic message + request_id |
| Staging | Detail + stack hash |
| Development | Full stack trace |
| Admin/debug header | Verbose with auth |
Warning: Never leak SQL, file paths, or stack traces to public clients — info disclosure (OWASP A05).
6. Setting Up Error Logging
| Field | Why |
| request_id | Correlate with client |
| trace_id | Link to distributed trace |
| user_id / api_key_hash | Identify caller |
| route + method | Locate problem |
| upstream status | Root cause |
| stack hash | Group identical errors |
7. Using Problem Details (RFC 7807)
| Field | Required | Description |
type | Yes | URI identifying problem |
title | Yes | Short summary |
status | Recommended | HTTP code |
detail | Optional | Specific to occurrence |
instance | Optional | URI of this occurrence |
| Extensions | Optional | Custom fields allowed |
8. Implementing Error Retry Logic
Example: Exponential backoff with jitter
int attempt = 0;
while (attempt < maxRetries) {
Response r = call();
if (r.status < 500 && r.status != 429) return r;
int baseMs = (int) Math.min(30000, 100 * Math.pow(2, attempt));
int sleep = ThreadLocalRandom.current().nextInt(baseMs / 2, baseMs);
Thread.sleep(sleep);
attempt++;
}
9. Configuring Fallback Responses
| Fallback Source | Use |
| Cached last-good | Serve stale |
| Static JSON | Empty list, default |
| Secondary upstream | Failover |
| Degraded mode flag | Client switches UX |
| Header | Use |
Content-Type: application/problem+json | RFC 7807 signal |
Retry-After | 429/503 hint |
X-Request-ID | Correlation |
WWW-Authenticate | 401 challenge |
Cache-Control: no-store | Don't cache errors |