Error Handling
Learn how to handle errors and exceptions when using our API.
Error Structure
Our API returns standardized error responses to help you identify and resolve issues quickly. All errors follow this structure:
{
"error": {
"code": "resource_not_found",
"message": "The requested resource was not found",
"details": {
"resource": "item",
"id": "non-existent-id"
},
"requestId": "req_1234567890"
}
}The error object contains the following fields:
| Field | Description |
|---|---|
code | A machine-readable error code that identifies the type of error |
message | A human-readable description of the error |
details | Additional context about the error (varies by error type) |
requestId | A unique identifier for the request, useful for troubleshooting with support |
Common Error Codes
Here are the most common error codes you might encounter:
| Error Code | HTTP Status | Description |
|---|---|---|
authentication_required | 401 | No valid authentication credentials were provided |
invalid_api_key | 401 | The API key provided is invalid or has been revoked |
permission_denied | 403 | The authenticated user doesn't have permission to perform the requested action |
resource_not_found | 404 | The requested resource doesn't exist |
validation_error | 422 | The request data failed validation |
rate_limit_exceeded | 429 | You've exceeded the rate limit for API requests |
internal_error | 500 | An unexpected error occurred on our servers |
service_unavailable | 503 | The service is temporarily unavailable, usually due to maintenance |
Handling Errors in Code
Our SDK provides built-in error handling mechanisms. Here's how to handle errors in your code:
import { Client, ApiError } from '@acme/sdk';
const client = new Client({
apiKey: 'YOUR_API_KEY',
});
// Basic error handling with try/catch
async function handleBasicErrors() {
try {
// This will fail if the item doesn't exist
const item = await client.items.get('non-existent-id');
return item;
} catch (error) {
if (error instanceof ApiError) {
console.error('API Error:', error.code, error.message);
console.error('Request ID:', error.requestId);
// Handle specific error types
if (error.code === 'resource_not_found') {
console.log('The requested item does not exist');
} else if (error.code === 'permission_denied') {
console.log('You do not have permission to access this item');
}
} else {
// Handle non-API errors (network issues, etc.)
console.error('Unexpected error:', error);
}
// Return a fallback or re-throw the error
return null;
}
}
// Handling validation errors
async function handleValidationErrors() {
try {
const newItem = await client.items.create({
// Missing required fields or invalid data
});
return newItem;
} catch (error) {
if (error instanceof ApiError && error.code === 'validation_error') {
console.error('Validation Error:', error.message);
// The details field contains validation errors for specific fields
if (error.details && error.details.fields) {
for (const [field, fieldErrors] of Object.entries(error.details.fields)) {
console.error(`Field "${field}" has errors: ${fieldErrors.join(', ')}`);
}
}
} else {
console.error('Unexpected error:', error);
}
return null;
}
}Retry Strategies
Some errors are transient and can be resolved by retrying the request. Here's how to implement retry logic:
When to Retry
Only retry requests for the following error types:
- Rate limiting (429) - with exponential backoff
- Server errors (500, 502, 503, 504) - temporary issues
- Network errors - connectivity issues
Do NOT retry for client errors (400, 401, 403, 404, 422) as they won't be resolved by retrying.
import { Client, ApiError } from '@acme/sdk';
const client = new Client({
apiKey: 'YOUR_API_KEY',
});
// Simple retry function with exponential backoff
async function withRetry(fn, maxRetries = 3, initialDelay = 1000) {
let retries = 0;
while (true) {
try {
return await fn();
} catch (error) {
// Don't retry if we've reached the maximum retries
if (retries >= maxRetries) {
throw error;
}
// Only retry for specific error types
if (error instanceof ApiError) {
const statusCode = error.statusCode;
// Don't retry client errors (except rate limiting)
if (statusCode >= 400 && statusCode < 500 && statusCode !== 429) {
throw error;
}
}
// Increment retry counter
retries++;
// Calculate delay with exponential backoff and jitter
const delay = initialDelay * Math.pow(2, retries - 1) * (0.5 + Math.random() * 0.5);
console.log(`Retrying after ${delay}ms (attempt ${retries} of ${maxRetries})`);
// Wait before retrying
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Example usage
async function fetchWithRetry() {
return withRetry(() => client.items.list());
}
// Example with rate limiting
async function handleRateLimiting() {
try {
const result = await withRetry(() => client.items.list(), 5, 2000);
return result;
} catch (error) {
if (error instanceof ApiError && error.code === 'rate_limit_exceeded') {
console.error('Rate limit exceeded even after retries');
// Get rate limit information from the error details
if (error.details && error.details.rateLimit) {
const { limit, remaining, reset } = error.details.rateLimit;
const resetDate = new Date(reset * 1000);
console.log(`Rate limit: ${limit}, Remaining: ${remaining}, Resets at: ${resetDate}`);
}
}
throw error;
}
}Debugging Tips
When troubleshooting API errors, consider these tips:
Enable Verbose Logging
Our SDK supports detailed logging to help with debugging:
import { Client } from '@acme/sdk';
const client = new Client({
apiKey: 'YOUR_API_KEY',
debug: true, // Enable debug mode
});
// You can also configure a custom logger
const clientWithCustomLogger = new Client({
apiKey: 'YOUR_API_KEY',
logger: {
debug: (message) => console.debug(`[ACME SDK] ${message}`),
info: (message) => console.info(`[ACME SDK] ${message}`),
warn: (message) => console.warn(`[ACME SDK] ${message}`),
error: (message) => console.error(`[ACME SDK] ${message}`),
},
});Check Request IDs
Every API response includes a unique request ID in both successful responses and errors. Always include this ID when contacting support about an issue.
Use the API Dashboard
Our API dashboard provides logs of recent requests, which can help identify issues. You can access it at dashboard.example.com/api-logs.