This documents the API gateway architecture and behavior. These are not callable endpoints — they describe how the gateway processes requests.
API Gateway Error Handling
Complete reference for error responses, status codes, and error handling patterns in the Olympus Cloud API Gateway.
Overview
All API errors follow a standardized format to ensure consistent client handling across all endpoints.
Design Principles
- Predictable Structure - All errors use the same JSON schema
- Actionable Messages - Clear guidance on how to resolve issues
- Traceable - Request IDs and timestamps for debugging
- Severity Aware - Indicates urgency and retry behavior
- Secure - Never exposes internal implementation details
Error Response Format
Standard Error Response
All errors return this structure:
{
"error": {
"id": "err-abc123-def456",
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": "The 'email' field must be a valid email address",
"timestamp": "2026-01-19T14:30:00Z",
"request_id": "req-xyz789",
"path": "/api/v1/users",
"method": "POST",
"status_code": 400,
"severity": "low",
"retryable": false,
"errors": [
{
"field": "email",
"message": "Invalid email format",
"code": "INVALID_FORMAT",
"value": "not-an-email"
}
],
"metadata": {
"allowed_formats": ["user@example.com"]
}
}
}
Field Descriptions
| Field | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique error identifier |
code | string | Yes | Machine-readable error code |
message | string | Yes | Human-readable error summary |
details | string | No | Extended explanation |
timestamp | string | Yes | ISO 8601 error timestamp |
request_id | string | Yes | Request tracking ID |
path | string | Yes | Request path |
method | string | Yes | HTTP method |
status_code | integer | Yes | HTTP status code |
severity | string | Yes | Error severity level |
retryable | boolean | Yes | Whether request can be retried |
errors | array | No | Field-level validation errors |
metadata | object | No | Additional context |
Lightweight Error Format (Middleware)
Authentication middleware returns a simplified format:
{
"error": "Unauthorized",
"code": "UNAUTHORIZED",
"message": "Authentication is required to access this resource.",
"request_id": "req-xyz789",
"timestamp": "2026-01-19T14:30:00Z"
}
Error Codes Reference
Authentication Errors (401)
| Code | HTTP | Message | Retryable |
|---|---|---|---|
UNAUTHORIZED | 401 | Authentication required | No |
INVALID_TOKEN | 401 | Token validation failed | No |
TOKEN_EXPIRED | 401 | Authentication token has expired | Yes* |
INVALID_CREDENTIALS | 401 | Invalid username or password | No |
SESSION_EXPIRED | 401 | Session has expired | No |
SESSION_REVOKED | 401 | Session was terminated | No |
*Retryable after token refresh
Authorization Errors (403)
| Code | HTTP | Message | Retryable |
|---|---|---|---|
FORBIDDEN | 403 | Access denied | No |
INSUFFICIENT_PERMISSIONS | 403 | Missing required permissions | No |
SHELL_ACCESS_DENIED | 403 | Not authorized for this shell | No |
STEP_UP_REQUIRED | 403 | Additional authentication required | Yes* |
MFA_REQUIRED | 403 | Multi-factor authentication required | Yes* |
*Retryable after completing authentication step
Validation Errors (400)
| Code | HTTP | Message | Retryable |
|---|---|---|---|
BAD_REQUEST | 400 | Invalid request | No |
VALIDATION_ERROR | 400 | Request validation failed | No |
MISSING_FIELD | 400 | Required field is missing | No |
INVALID_FORMAT | 400 | Field format is invalid | No |
INVALID_VALUE | 400 | Field value is not allowed | No |
INVALID_JSON | 400 | Request body is not valid JSON | No |
CONTENT_TOO_LARGE | 413 | Request body exceeds size limit | No |
UNSUPPORTED_MEDIA_TYPE | 415 | Content-Type not supported | No |
Resource Errors (404/409)
| Code | HTTP | Message | Retryable |
|---|---|---|---|
NOT_FOUND | 404 | Resource not found | No |
ALREADY_EXISTS | 409 | Resource already exists | No |
CONFLICT | 409 | Resource state conflict | Yes* |
RESOURCE_LOCKED | 409 | Resource is locked | Yes |
DUPLICATE_ENTRY | 409 | Duplicate value detected | No |
*Retryable after resolving conflict
Business Logic Errors (409)
| Code | HTTP | Message | Retryable |
|---|---|---|---|
BUSINESS_LOGIC_ERROR | 409 | Business rule violation | No |
INSUFFICIENT_FUNDS | 409 | Insufficient balance | No |
ORDER_NOT_CANCELABLE | 409 | Order cannot be cancelled | No |
TABLE_OCCUPIED | 409 | Table is currently occupied | Yes |
MENU_ITEM_UNAVAILABLE | 409 | Menu item is 86'd | No |
INVENTORY_INSUFFICIENT | 409 | Not enough inventory | No |
RESERVATION_CONFLICT | 409 | Time slot unavailable | Yes |
Service Errors (5xx)
All 5xx errors and 429 rate limit errors are retryable. Use exponential backoff for 5xx errors and respect the Retry-After header for 429 responses. Non-retryable errors (most 4xx) indicate a problem with the request itself and should not be retried without modification.
| Code | HTTP | Message | Retryable |
|---|---|---|---|
INTERNAL_SERVER_ERROR | 500 | An unexpected error occurred | Yes |
BAD_GATEWAY | 502 | Upstream service error | Yes |
SERVICE_UNAVAILABLE | 503 | Service temporarily unavailable | Yes |
TIMEOUT | 504 | Request timed out | Yes |
RATE_LIMIT_EXCEEDED | 429 | Too many requests | Yes* |
*Retryable after waiting for rate limit reset
Severity Levels
| Severity | Description | Client Action |
|---|---|---|
low | Validation errors, missing resources | Fix request and retry |
medium | Conflicts, rate limits | Wait and retry or fix conflict |
high | Authentication, authorization failures | Re-authenticate or escalate |
critical | Internal server errors | Report to support |
Validation Error Details
When validation fails, the errors array contains field-level details:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"errors": [
{
"field": "email",
"message": "Must be a valid email address",
"code": "INVALID_FORMAT",
"value": "not-valid"
},
{
"field": "phone",
"message": "Phone number is required",
"code": "MISSING_FIELD",
"value": null
},
{
"field": "age",
"message": "Must be 18 or older",
"code": "INVALID_VALUE",
"value": 16
}
]
}
}
Field Error Structure
| Field | Type | Description |
|---|---|---|
field | string | JSON path to the invalid field |
message | string | Human-readable validation message |
code | string | Validation error code |
value | any | The invalid value (sanitized) |
Nested Field Paths
For nested objects, field paths use dot notation:
{
"errors": [
{
"field": "address.zip_code",
"message": "Invalid ZIP code format"
},
{
"field": "items[0].quantity",
"message": "Quantity must be positive"
}
]
}
Rate Limiting Errors
When rate limits are exceeded:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Please slow down.",
"details": "Rate limit: 100 requests per minute",
"severity": "medium",
"retryable": true,
"metadata": {
"limit": 100,
"window": "1m",
"retry_after": 45,
"reset_at": "2026-01-19T14:31:00Z"
}
}
}
Rate Limit Headers
Rate limit information is also provided in response headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1737296460
Retry-After: 45
Service-Specific Errors
Commerce Service
{
"error": {
"code": "ORDER_NOT_CANCELABLE",
"message": "Order cannot be cancelled",
"details": "Order has already been sent to kitchen",
"metadata": {
"order_id": "order-12345",
"order_status": "preparing",
"cancelable_statuses": ["open", "pending"]
}
}
}
Inventory Service
{
"error": {
"code": "INVENTORY_INSUFFICIENT",
"message": "Insufficient inventory for order",
"details": "Not enough 'Chicken Breast' in stock",
"metadata": {
"item_id": "inv-chicken",
"requested": 5,
"available": 2,
"unit": "lb"
}
}
}
Payment Service
{
"error": {
"code": "PAYMENT_DECLINED",
"message": "Payment was declined",
"details": "Card declined by issuer",
"metadata": {
"decline_code": "insufficient_funds",
"last_four": "4242",
"card_brand": "visa"
}
}
}
Error Handling Best Practices
Client-Side Handling
TypeScript Example
interface APIError {
error: {
id: string;
code: string;
message: string;
details?: string;
timestamp: string;
request_id: string;
status_code: number;
severity: 'low' | 'medium' | 'high' | 'critical';
retryable: boolean;
errors?: FieldError[];
metadata?: Record<string, unknown>;
};
}
interface FieldError {
field: string;
message: string;
code: string;
value?: unknown;
}
async function handleAPIError(error: APIError): Promise<void> {
const { code, severity, retryable, errors } = error.error;
switch (code) {
case 'TOKEN_EXPIRED':
await refreshToken();
break;
case 'VALIDATION_ERROR':
displayFieldErrors(errors);
break;
case 'RATE_LIMIT_EXCEEDED':
const retryAfter = error.error.metadata?.retry_after;
await delay(retryAfter * 1000);
break;
case 'STEP_UP_REQUIRED':
redirectToMFA();
break;
default:
if (severity === 'critical') {
reportToErrorTracking(error);
}
displayGenericError(error.error.message);
}
}
Retry Logic
async function fetchWithRetry<T>(
url: string,
options: RequestInit,
maxRetries = 3
): Promise<T> {
let lastError: APIError | null = null;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.ok) {
return response.json();
}
const error: APIError = await response.json();
lastError = error;
// Don't retry non-retryable errors
if (!error.error.retryable) {
throw error;
}
// Handle rate limiting
if (error.error.code === 'RATE_LIMIT_EXCEEDED') {
const retryAfter = error.error.metadata?.retry_after || 60;
await delay(retryAfter * 1000);
continue;
}
// Exponential backoff for other retryable errors
await delay(Math.pow(2, attempt) * 1000);
} catch (networkError) {
// Network errors are retryable
await delay(Math.pow(2, attempt) * 1000);
}
}
throw lastError || new Error('Max retries exceeded');
}
Logging and Debugging
Every error response includes a unique request_id field. Always log this value on the client side. When contacting support, providing the request_id and timestamp allows the operations team to quickly locate the exact request in distributed traces and logs.
Always log the request_id for support escalation:
console.error('API Error:', {
requestId: error.error.request_id,
code: error.error.code,
message: error.error.message,
timestamp: error.error.timestamp
});
When contacting support, provide:
request_idfrom the error responsetimestampof the error- Request method and path
- Any relevant context
HTTP Status Code Summary
| Status | Category | Description |
|---|---|---|
| 400 | Client Error | Bad request, validation failed |
| 401 | Client Error | Authentication required |
| 403 | Client Error | Permission denied |
| 404 | Client Error | Resource not found |
| 405 | Client Error | Method not allowed |
| 409 | Client Error | Conflict or business rule violation |
| 413 | Client Error | Payload too large |
| 415 | Client Error | Unsupported media type |
| 422 | Client Error | Unprocessable entity |
| 429 | Client Error | Rate limit exceeded |
| 500 | Server Error | Internal server error |
| 502 | Server Error | Bad gateway |
| 503 | Server Error | Service unavailable |
| 504 | Server Error | Gateway timeout |
Troubleshooting Guide
Common Error Scenarios
"INVALID_TOKEN" After App Update
Cause: Token format changed in new version.
Solution: Clear stored tokens and re-authenticate.
localStorage.removeItem('access_token');
localStorage.removeItem('refresh_token');
redirectToLogin();
"RATE_LIMIT_EXCEEDED" During Bulk Operations
Cause: Too many requests in short period.
Solution: Implement request batching and throttling.
const batchSize = 10;
const delayMs = 1000;
for (let i = 0; i < items.length; i += batchSize) {
const batch = items.slice(i, i + batchSize);
await Promise.all(batch.map(processItem));
await delay(delayMs);
}
"SERVICE_UNAVAILABLE" Intermittently
Cause: Backend service scaling or deployment.
Solution: Implement retry with exponential backoff.
"CONFLICT" on Resource Update
Cause: Another request modified the resource.
Solution: Fetch latest resource and merge changes.
try {
await updateResource(id, changes);
} catch (error) {
if (error.error.code === 'CONFLICT') {
const latest = await getResource(id);
const merged = mergeChanges(latest, changes);
await updateResource(id, merged);
}
}
Related Documentation
- API Gateway Architecture - Gateway overview
- Rate Limiting - Request throttling
- Authentication - Auth middleware
- WebSocket Events - Real-time errors