Error Handling
How to handle API errors.
Error Response Format
All errors return a consistent JSON structure:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable description",
"details": {}
}
}HTTP Status Codes
| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 204 | No Content (successful delete) |
| 400 | Bad Request - Invalid input |
| 401 | Unauthorized - Authentication required |
| 403 | Forbidden - Insufficient permissions |
| 404 | Not Found - Resource doesn't exist |
| 409 | Conflict - Resource already exists |
| 422 | Unprocessable Entity - Validation error |
| 429 | Too Many Requests - Rate limited |
| 500 | Internal Server Error |
| 503 | Service Unavailable |
Common Error Codes
Authentication Errors
UNAUTHORIZED
{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required"
}
}INVALID_API_KEY
{
"error": {
"code": "INVALID_API_KEY",
"message": "Invalid or expired API key"
}
}FORBIDDEN
{
"error": {
"code": "FORBIDDEN",
"message": "Insufficient permissions",
"details": {
"required": "components:write"
}
}
}Validation Errors
VALIDATION_ERROR
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request body",
"details": {
"field": "name",
"message": "Name is required"
}
}
}INVALID_FORMAT
{
"error": {
"code": "INVALID_FORMAT",
"message": "Invalid date format",
"details": {
"field": "scheduledStartAt",
"expected": "ISO 8601"
}
}
}Resource Errors
NOT_FOUND
{
"error": {
"code": "NOT_FOUND",
"message": "Component not found",
"details": {
"resource": "component",
"id": "comp_123"
}
}
}CONFLICT
{
"error": {
"code": "CONFLICT",
"message": "Component with this name already exists"
}
}Rate Limiting
RATE_LIMIT_EXCEEDED
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests",
"details": {
"limit": 100,
"window": "60s",
"retryAfter": 45
}
}
}Server Errors
INTERNAL_ERROR
{
"error": {
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred"
}
}Handling Errors
Example: JavaScript
async function createIncident(data) {
const response = await fetch('/api/v1/incidents', {
method: 'POST',
headers: {
'Authorization': 'Bearer sk_live_xxx',
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
if (!response.ok) {
const error = await response.json();
switch (error.error.code) {
case 'VALIDATION_ERROR':
console.error('Invalid input:', error.error.details);
break;
case 'UNAUTHORIZED':
// Redirect to login or refresh token
break;
case 'RATE_LIMIT_EXCEEDED':
// Wait and retry
const retryAfter = error.error.details.retryAfter;
await new Promise(r => setTimeout(r, retryAfter * 1000));
return createIncident(data);
default:
throw new Error(error.error.message);
}
}
return response.json();
}Example: Python
import requests
import time
def create_incident(data):
response = requests.post(
'https://api.example.com/api/v1/incidents',
headers={'Authorization': 'Bearer sk_live_xxx'},
json=data
)
if response.status_code == 429:
retry_after = response.json()['error']['details']['retryAfter']
time.sleep(retry_after)
return create_incident(data)
if response.status_code >= 400:
error = response.json()['error']
raise Exception(f"{error['code']}: {error['message']}")
return response.json()Retry Logic
When to Retry
| Status | Retry? | Strategy |
|---|---|---|
| 429 | Yes | Wait for retryAfter |
| 500 | Yes | Exponential backoff |
| 502 | Yes | Exponential backoff |
| 503 | Yes | Exponential backoff |
| 504 | Yes | Exponential backoff |
| 400 | No | Fix request |
| 401 | No | Check credentials |
| 403 | No | Check permissions |
| 404 | No | Check resource ID |
Exponential Backoff
async function retryWithBackoff(fn, maxRetries = 3) {
let lastError;
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
lastError = error;
if (i < maxRetries - 1) {
const delay = Math.pow(2, i) * 1000; // 1s, 2s, 4s
await new Promise(r => setTimeout(r, delay));
}
}
}
throw lastError;
}Request IDs
Every response includes a request ID header:
X-Request-Id: req_abc123xyzInclude this when contacting support for faster debugging.
Best Practices
- Always check status codes before parsing response
- Handle rate limits gracefully with retry logic
- Log error details for debugging
- Use request IDs when reporting issues
- Validate input before sending to reduce errors