Understand and handle API errors effectively.
When an error occurs, the API returns a structured error response:
{
"detail": "Error message describing what went wrong",
"error_code": "SPECIFIC_ERROR_CODE",
"field_errors": {
"field_name": ["Field-specific error message"]
}
}| Code | Error | Meaning |
|---|---|---|
400 | Bad Request | Invalid request format or parameters |
401 | Unauthorized | Missing or invalid authentication |
403 | Forbidden | Valid auth but insufficient permissions |
404 | Not Found | Resource doesn't exist |
409 | Conflict | Request conflicts with current state |
422 | Unprocessable Entity | Validation error |
429 | Too Many Requests | Rate limit exceeded |
| Code | Error | Meaning |
|---|---|---|
500 | Internal Server Error | Something went wrong on our end |
502 | Bad Gateway | Temporary service issue |
503 | Service Unavailable | Service temporarily unavailable |
504 | Gateway Timeout | Request took too long |
Cause: Malformed JSON or invalid parameters
{
"detail": "JSON parse error - Expecting value"
}Solution: Validate your JSON syntax and request parameters.
Cause: Missing or invalid API token
{
"detail": "Authentication credentials were not provided."
}Solution: Check that you're including the Authorization header with a valid token.
Cause: Insufficient permissions
{
"detail": "You do not have permission to perform this action."
}Solution: Verify your user role has the required permissions for this operation.
Cause: Resource doesn't exist
{
"detail": "Not found."
}Solution: Verify the resource ID and ensure it exists.
Cause: Invalid field values
{
"identifier": ["This field is required."],
"assessment_type": ["Invalid choice."]
}Solution: Review the field errors and fix the invalid values.
Cause: Too many requests
{
"detail": "Request was throttled. Expected available in 3600 seconds."
}Solution: Implement exponential backoff and respect rate limits.
async function makeApiCall(url: string) {
try {
const response = await fetch(url, {
headers: {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json'
}
});
if (!response.ok) {
const error = await response.json();
switch (response.status) {
case 400:
throw new ValidationError(error.detail);
case 401:
throw new AuthenticationError('Invalid token');
case 403:
throw new PermissionError('Insufficient permissions');
case 404:
throw new NotFoundError('Resource not found');
case 429:
throw new RateLimitError('Rate limit exceeded');
default:
throw new APIError(error.detail);
}
}
return await response.json();
} catch (error) {
console.error('API Error:', error);
throw error;
}
}import requests
from requests.exceptions import HTTPError
class APIError(Exception):
pass
class AuthenticationError(APIError):
pass
class ValidationError(APIError):
pass
def make_api_call(url):
try:
response = requests.get(
url,
headers={
'Authorization': f'Bearer {API_TOKEN}',
'Content-Type': 'application/json'
}
)
response.raise_for_status()
return response.json()
except HTTPError as e:
status_code = e.response.status_code
error_data = e.response.json()
if status_code == 401:
raise AuthenticationError('Invalid token')
elif status_code == 422:
raise ValidationError(error_data)
elif status_code == 429:
# Implement retry logic
time.sleep(60)
return make_api_call(url)
else:
raise APIError(error_data.get('detail'))For transient errors (429, 5xx), implement exponential backoff:
import time
from typing import Optional
def make_request_with_retry(
url: str,
max_retries: int = 3,
backoff_factor: int = 2
) -> Optional[dict]:
for attempt in range(max_retries):
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
status_code = e.response.status_code
# Don't retry client errors (except rate limit)
if 400 <= status_code < 500 and status_code != 429:
raise
# Calculate wait time
wait_time = backoff_factor ** attempt
if attempt < max_retries - 1:
print(f"Retry {attempt + 1}/{max_retries} after {wait_time}s")
time.sleep(wait_time)
else:
raiseHandle field-level validation errors:
interface ValidationErrorResponse {
[field: string]: string[];
}
function handleValidationError(errors: ValidationErrorResponse) {
const formattedErrors = Object.entries(errors).map(
([field, messages]) => ({
field,
message: messages.join(', ')
})
);
// Display errors to user
formattedErrors.forEach(({ field, message }) => {
showFieldError(field, message);
});
}✅ Do log:
- Error messages and codes
- Request IDs (if provided)
- Timestamp
- Endpoint and method
- Status code
❌ Don't log:
- API tokens
- Sensitive user data
- Personal information
function logApiError(error, context) {
console.error({
timestamp: new Date().toISOString(),
endpoint: context.url,
method: context.method,
status: error.status,
message: error.message,
// Don't log: token, user data
});
}- Always check status codes before processing responses
- Implement retry logic for 429 and 5xx errors
- Validate data client-side before sending to reduce 422 errors
- Display user-friendly messages instead of raw API errors
- Monitor error rates to detect issues early
- Cache tokens to avoid authentication errors
- Handle network failures gracefully
If you encounter persistent errors:
- Check API Status
- Review the API Reference
- Contact support@coolset.com
Include these details when reporting errors:
- Timestamp
- Endpoint and method
- Status code and error message
- Request ID (if available)