Last Updated: 1/27/2026
Error Handling
Handle API errors gracefully in your application.
Error Types
import {
ApiError,
NetworkError,
ValidationError,
RateLimitError,
AuthenticationError,
} from '@example/sdk';| Error Type | Cause | Recovery |
|---|---|---|
ApiError | API returned an error | Check error code |
NetworkError | Connection failed | Retry with backoff |
ValidationError | Invalid input | Fix input data |
RateLimitError | Too many requests | Wait and retry |
AuthenticationError | Invalid credentials | Check API key |
:::info
All errors extend the base ApiError class with additional context.
:::
Basic Error Handling
import { createClient, ApiError } from '@example/sdk';
const client = createClient({ apiKey: process.env.API_KEY! });
try {
const user = await client.users.get('user_123');
console.log(user);
} catch (error) {
if (error instanceof ApiError) {
console.error(`Error ${error.code}: ${error.message}`);
} else {
throw error; // Re-throw unexpected errors
}
}Specific Error Handling
import {
ApiError,
ValidationError,
RateLimitError,
AuthenticationError,
NotFoundError,
} from '@example/sdk';
async function getUser(id: string) {
try {
return await client.users.get(id);
} catch (error) {
if (error instanceof NotFoundError) {
console.log(`User ${id} not found`);
return null;
}
if (error instanceof ValidationError) {
console.error('Invalid input:', error.issues);
// [{ field: 'id', message: 'Must be a valid UUID' }]
throw error;
}
if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter}ms`);
await sleep(error.retryAfter);
return getUser(id); // Retry
}
if (error instanceof AuthenticationError) {
console.error('Invalid API key');
throw error;
}
throw error;
}
}:::warning
Always handle RateLimitError with exponential backoff to avoid being blocked.
:::
Error Properties
try {
await client.users.create({ email: 'invalid' });
} catch (error) {
if (error instanceof ApiError) {
console.log('Code:', error.code); // 'VALIDATION_ERROR'
console.log('Message:', error.message); // 'Invalid email format'
console.log('Status:', error.status); // 400
console.log('Request ID:', error.requestId); // 'req_abc123'
// For validation errors
if (error instanceof ValidationError) {
console.log('Issues:', error.issues);
// [{ field: 'email', message: 'Invalid email format' }]
}
}
}:::tip
Include the requestId when contacting support for faster debugging.
:::
Retry Logic
import { createClient, RateLimitError, NetworkError } from '@example/sdk';
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
): Promise<T> {
let lastError: Error | undefined;
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error as Error;
// Don't retry validation or auth errors
if (error instanceof ValidationError) throw error;
if (error instanceof AuthenticationError) throw error;
// Retry rate limits and network errors
if (error instanceof RateLimitError) {
await sleep(error.retryAfter);
continue;
}
if (error instanceof NetworkError) {
const backoff = Math.pow(2, attempt) * 1000;
console.log(`Retry ${attempt}/${maxRetries} in ${backoff}ms`);
await sleep(backoff);
continue;
}
throw error;
}
}
throw lastError;
}
// Usage
const user = await withRetry(() => client.users.get('user_123'));:::danger Set a maximum retry limit to prevent infinite loops. 3-5 retries is typically sufficient. :::
Global Error Handler
const client = createClient({
apiKey: process.env.API_KEY!,
onError: (error) => {
// Log all errors to monitoring service
logger.error('API Error', {
code: error.code,
message: error.message,
requestId: error.requestId,
});
// Send to error tracking
Sentry.captureException(error);
},
});:::note
The onError hook is called for all errors, even those you catch locally.
:::