Error handling
How to handle errors from the Synjar API.
Error response format
All errors return a consistent JSON structure:
{
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error message",
"details": {}
}
}
HTTP status codes
| Status | Meaning | Retry |
|---|---|---|
| 400 | Bad request - Invalid input | No |
| 401 | Unauthorized - Invalid auth | No |
| 403 | Forbidden - Insufficient permissions | No |
| 404 | Not found - Resource doesn't exist | No |
| 409 | Conflict - Resource state conflict | Maybe |
| 413 | Payload too large - File too big | No |
| 429 | Rate limited - Too many requests | Yes |
| 500 | Internal error - Server issue | Yes |
| 503 | Service unavailable - Maintenance | Yes |
Error codes reference
Authentication errors
| Code | HTTP | Description |
|---|---|---|
UNAUTHORIZED | 401 | Missing or invalid token |
TOKEN_EXPIRED | 401 | Token has expired |
INVALID_CREDENTIALS | 401 | Wrong email/password |
FORBIDDEN | 403 | Insufficient permissions |
Validation errors
| Code | HTTP | Description |
|---|---|---|
VALIDATION_ERROR | 400 | Invalid input data |
MISSING_FIELD | 400 | Required field missing |
INVALID_FORMAT | 400 | Field format invalid |
Resource errors
| Code | HTTP | Description |
|---|---|---|
NOT_FOUND | 404 | Resource not found |
ALREADY_EXISTS | 409 | Resource already exists |
CONFLICT | 409 | Resource state conflict |
Document errors
| Code | HTTP | Description |
|---|---|---|
FILE_TOO_LARGE | 413 | Exceeds size limit |
UNSUPPORTED_FORMAT | 400 | File type not supported |
PROCESSING_FAILED | 500 | Document processing error |
Rate limit errors
| Code | HTTP | Description |
|---|---|---|
RATE_LIMITED | 429 | Too many requests |
Handling errors
JavaScript example
async function apiRequest(url, options) {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 401:
// Handle auth error - redirect to login
throw new AuthError(error.error.message);
case 429:
// Rate limited - retry after delay
const retryAfter = response.headers.get('Retry-After') || 60;
await sleep(retryAfter * 1000);
return apiRequest(url, options);
case 500:
case 503:
// Server error - retry with backoff
throw new ServerError(error.error.message);
default:
throw new ApiError(error.error.code, error.error.message);
}
}
return response.json();
}
Python example
import requests
import time
def api_request(url, **kwargs):
response = requests.request(url=url, **kwargs)
if response.status_code == 429:
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
return api_request(url, **kwargs)
if response.status_code >= 500:
raise ServerError(response.json()['error']['message'])
if not response.ok:
error = response.json()['error']
raise ApiError(error['code'], error['message'])
return response.json()
Rate limit handling
When you receive a 429 response:
- Check
Retry-Afterheader for wait time - Wait the specified seconds
- Retry the request
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
console.log(`Rate limited. Waiting ${retryAfter}s...`);
await new Promise(r => setTimeout(r, retryAfter * 1000));
return retry(request);
}
Exponential backoff
For 5xx errors, use exponential backoff:
async function withRetry(fn, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (i === maxRetries - 1) throw error;
if (error.status < 500) throw error;
const delay = Math.pow(2, i) * 1000;
await new Promise(r => setTimeout(r, delay));
}
}
}