Error Handling¶
Complete guide to API error codes and handling strategies.
Error Response Format¶
All API errors follow a consistent structure:
{
"error": "error_code",
"code": "ERROR_CODE",
"message": "Human-readable error description",
"details": {
"field": "additional context"
}
}
HTTP Status Codes¶
| Status | Meaning | Description |
|---|---|---|
200 | OK | Request succeeded |
201 | Created | Resource created |
400 | Bad Request | Invalid request data |
401 | Unauthorized | Authentication failed |
403 | Forbidden | Insufficient permissions |
404 | Not Found | Resource not found |
409 | Conflict | Resource conflict |
413 | Payload Too Large | Request too large |
415 | Unsupported Media Type | Invalid file type |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server error |
503 | Service Unavailable | Service temporarily down |
Common Error Codes¶
Authentication Errors (401)¶
UNAUTHORIZED¶
Solutions: - Include authentication header - Verify token/API key is valid - Check token hasn't expired
INVALID_CREDENTIALS¶
{
"error": "invalid_credentials",
"code": "INVALID_CREDENTIALS",
"message": "Invalid email or password"
}
TOKEN_EXPIRED¶
Solution: Refresh the token using /api/v1/auth/refresh
Authorization Errors (403)¶
FORBIDDEN¶
{
"error": "forbidden",
"code": "FORBIDDEN",
"message": "You don't have permission to access this resource"
}
CSRF_TOKEN_REQUIRED¶
{
"error": "csrf_token_required",
"code": "CSRF_TOKEN_REQUIRED",
"message": "CSRF token is required for this request"
}
Solution: Get CSRF token from /api/v1/auth/csrf-token
Validation Errors (400)¶
VALIDATION_ERROR¶
{
"error": "validation_error",
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": {
"field": "email",
"message": "Invalid email format"
}
}
MISSING_REQUIRED_FIELD¶
{
"error": "missing_required_field",
"code": "MISSING_REQUIRED_FIELD",
"message": "Required field 'email' is missing",
"details": {
"field": "email"
}
}
Resource Errors (404)¶
NOT_FOUND¶
File Upload Errors¶
FILE_TOO_LARGE (413)¶
{
"error": "file_too_large",
"code": "FILE_TOO_LARGE",
"message": "File size exceeds maximum limit of 500MB"
}
INVALID_FILE_TYPE (415)¶
{
"error": "invalid_file_type",
"code": "INVALID_FILE_TYPE",
"message": "File type not supported. Supported types: pdf, docx, txt, jpg, png"
}
Rate Limit Errors (429)¶
RATE_LIMIT_EXCEEDED¶
{
"error": "rate_limit_exceeded",
"code": "RATE_LIMIT_EXCEEDED",
"message": "Rate limit exceeded. Please try again later.",
"details": {
"limit": 120,
"remaining": 0,
"reset_at": "2026-01-18T10:31:00Z"
}
}
Solution: Wait until reset_at timestamp, then retry
Error Handling Patterns¶
Basic Error Handling¶
async function makeRequest() {
try {
const response = await fetch('https://api.archivus.app/api/v1/documents', {
headers: { 'X-API-Key': apiKey }
});
if (!response.ok) {
const error = await response.json();
throw new Error(`${error.code}: ${error.message}`);
}
return await response.json();
} catch (error) {
console.error('API Error:', error);
throw error;
}
}
def make_request():
try:
response = requests.get(
'https://api.archivus.app/api/v1/documents',
headers={'X-API-Key': api_key}
)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
error = response.json()
print(f"API Error: {error['code']}: {error['message']}")
raise
Specific Error Handling¶
async function uploadDocument(file) {
try {
const response = await client.documents.upload(file);
return response;
} catch (error) {
switch (error.code) {
case 'FILE_TOO_LARGE':
console.error('File is too large. Max size: 500MB');
break;
case 'INVALID_FILE_TYPE':
console.error('Unsupported file type');
break;
case 'RATE_LIMIT_EXCEEDED':
// Wait and retry
await sleep(error.details.reset_at);
return uploadDocument(file);
default:
console.error('Unexpected error:', error);
}
throw error;
}
}
def upload_document(file):
try:
return client.documents.upload(file)
except APIError as e:
if e.code == 'FILE_TOO_LARGE':
print('File is too large. Max size: 500MB')
elif e.code == 'INVALID_FILE_TYPE':
print('Unsupported file type')
elif e.code == 'RATE_LIMIT_EXCEEDED':
# Wait and retry
time.sleep(parse_time(e.details['reset_at']))
return upload_document(file)
else:
print(f'Unexpected error: {e}')
raise
Retry Logic with Exponential Backoff¶
async function makeRequestWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
// Rate limited - wait and retry
const retryAfter = response.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000);
continue;
}
if (response.status >= 500) {
// Server error - retry with exponential backoff
const waitTime = Math.pow(2, attempt) * 1000;
await sleep(waitTime);
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
await sleep(Math.pow(2, attempt) * 1000);
}
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
import time
from requests.exceptions import RequestException
def make_request_with_retry(url, headers, max_retries=3):
for attempt in range(max_retries):
try:
response = requests.get(url, headers=headers)
if response.status_code == 429:
# Rate limited - wait and retry
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
continue
if response.status_code >= 500:
# Server error - retry with exponential backoff
wait_time = 2 ** attempt
time.sleep(wait_time)
continue
response.raise_for_status()
return response.json()
except RequestException as e:
if attempt == max_retries - 1:
raise
time.sleep(2 ** attempt)
return None
Error Code Reference¶
Authentication (401)¶
UNAUTHORIZED- Authentication requiredINVALID_CREDENTIALS- Invalid email/passwordTOKEN_EXPIRED- JWT token expiredINVALID_API_KEY- Invalid or revoked API key
Authorization (403)¶
FORBIDDEN- Insufficient permissionsCSRF_TOKEN_REQUIRED- CSRF token missing
Validation (400)¶
VALIDATION_ERROR- Request validation failedMISSING_REQUIRED_FIELD- Required field missingINVALID_QUERY- Invalid search query
Not Found (404)¶
NOT_FOUND- Resource not foundDOCUMENT_NOT_FOUND- Document not foundFOLDER_NOT_FOUND- Folder not found
Conflict (409)¶
DUPLICATE_RESOURCE- Resource already existsFOLDER_NOT_EMPTY- Folder contains documents
Rate Limits (429)¶
RATE_LIMIT_EXCEEDED- Too many requests
Server Errors (500)¶
INTERNAL_ERROR- Internal server errorSERVICE_UNAVAILABLE- Service temporarily unavailable
Best Practices¶
1. Always Check Status Codes¶
if (response.status === 401) {
// Refresh token and retry
} else if (response.status === 429) {
// Wait for rate limit reset
} else if (response.status >= 500) {
// Retry with backoff
}
2. Log Errors for Debugging¶
console.error('API Error:', {
code: error.code,
message: error.message,
details: error.details,
timestamp: new Date().toISOString()
});
3. Provide User-Friendly Messages¶
const userMessages = {
'FILE_TOO_LARGE': 'File is too large. Please upload a file smaller than 500MB.',
'INVALID_FILE_TYPE': 'This file type is not supported. Please upload a PDF, Word, or image file.',
'RATE_LIMIT_EXCEEDED': 'Too many requests. Please try again in a few minutes.'
};
const userMessage = userMessages[error.code] || 'An error occurred. Please try again.';
showNotification(userMessage);
Next Steps¶
-
Upload Documents
Handle upload errors properly
-
Authentication
Handle authentication errors