The Anthropic SDK provides comprehensive error classes for different failure scenarios. All errors extend from the base AnthropicError class and provide detailed information for debugging and recovery.
AnthropicError
├── APIError<TStatus, THeaders, TError>
│ ├── BadRequestError (400)
│ ├── AuthenticationError (401)
│ ├── PermissionDeniedError (403)
│ ├── NotFoundError (404)
│ ├── ConflictError (409)
│ ├── UnprocessableEntityError (422)
│ ├── RateLimitError (429)
│ └── InternalServerError (5xx)
├── APIConnectionError
│ └── APIConnectionTimeoutError
└── APIUserAbortErrorclass AnthropicError extends Error {
readonly name: string;
readonly message: string;
readonly cause?: Error;
}All SDK errors inherit from AnthropicError.
class APIError<TStatus = number, THeaders = Headers, TError = any> extends AnthropicError {
readonly status: TStatus; // HTTP status code
readonly headers: THeaders; // Response headers
readonly error: TError; // Error details from API
readonly requestID: string | null; // Request ID for debugging
}Example:
try {
const message = await client.messages.create({ /* ... */ });
} catch (error) {
if (error instanceof Anthropic.APIError) {
console.error('Status:', error.status);
console.error('Message:', error.message);
console.error('Request ID:', error.requestID);
console.error('Error details:', error.error);
}
}Invalid request parameters or malformed request.
class BadRequestError extends APIError<400> {}Common Causes:
Example:
try {
const message = await client.messages.create({
model: 'invalid-model',
max_tokens: 1024,
messages: [{ role: 'user', content: 'Hello' }],
});
} catch (error) {
if (error instanceof Anthropic.BadRequestError) {
console.error('Invalid request:', error.message);
// "model: invalid-model is not a valid model"
}
}Authentication failed - invalid or missing API key.
class AuthenticationError extends APIError<401> {}Common Causes:
Example:
try {
const client = new Anthropic({ apiKey: 'invalid-key' });
await client.messages.create({ /* ... */ });
} catch (error) {
if (error instanceof Anthropic.AuthenticationError) {
console.error('Authentication failed');
// Check API key configuration
}
}Insufficient permissions for the requested operation.
class PermissionDeniedError extends APIError<403> {}Common Causes:
Example:
try {
await client.beta.messages.create({
betas: ['restricted-feature'],
/* ... */
});
} catch (error) {
if (error instanceof Anthropic.PermissionDeniedError) {
console.error('Access denied to beta feature');
}
}Requested resource not found.
class NotFoundError extends APIError<404> {}Common Causes:
Example:
try {
const batch = await client.messages.batches.retrieve('nonexistent-id');
} catch (error) {
if (error instanceof Anthropic.NotFoundError) {
console.error('Batch not found');
}
}Request conflicts with current state.
class ConflictError extends APIError<409> {}Common Causes:
Example:
try {
await client.beta.skills.create({
name: 'existing-skill', // Already exists
/* ... */
});
} catch (error) {
if (error instanceof Anthropic.ConflictError) {
console.error('Skill already exists');
}
}Request is syntactically correct but semantically invalid.
class UnprocessableEntityError extends APIError<422> {}Common Causes:
Example:
try {
await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 1024,
messages: [
{ role: 'assistant', content: 'Cannot start with assistant' },
],
});
} catch (error) {
if (error instanceof Anthropic.UnprocessableEntityError) {
console.error('Invalid message structure');
}
}Rate limit exceeded.
class RateLimitError extends APIError<429> {}Common Causes:
Example:
try {
await client.messages.create({ /* ... */ });
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
console.error('Rate limited');
// Get retry information from headers
const retryAfter = error.headers.get('retry-after');
const resetTime = error.headers.get('x-ratelimit-reset');
console.log(`Retry after: ${retryAfter} seconds`);
console.log(`Resets at: ${new Date(parseInt(resetTime) * 1000)}`);
// Implement backoff
await new Promise(resolve => setTimeout(resolve, parseInt(retryAfter) * 1000));
}
}Server-side error.
class InternalServerError extends APIError<500 | 502 | 503 | 504> {}Common Causes:
Example:
try {
await client.messages.create({ /* ... */ });
} catch (error) {
if (error instanceof Anthropic.InternalServerError) {
console.error('Server error:', error.status);
// Retry with exponential backoff
await retryWithBackoff(() => client.messages.create({ /* ... */ }));
}
}Failed to connect to the API.
class APIConnectionError extends AnthropicError {
readonly cause?: Error;
}Common Causes:
Example:
try {
await client.messages.create({ /* ... */ });
} catch (error) {
if (error instanceof Anthropic.APIConnectionError) {
console.error('Network error:', error.message);
console.error('Cause:', error.cause);
// Check network connectivity
// Retry with exponential backoff
}
}Request timed out.
class APIConnectionTimeoutError extends APIConnectionError {}Common Causes:
Example:
try {
await client.messages.create(
{
model: 'claude-sonnet-4-5-20250929',
max_tokens: 10000,
messages: [{ role: 'user', content: 'Long task' }],
},
{ timeout: 30000 } // 30 seconds
);
} catch (error) {
if (error instanceof Anthropic.APIConnectionTimeoutError) {
console.error('Request timed out');
// Use streaming for long requests
const stream = client.messages.stream({ /* ... */ });
}
}User aborted the request.
class APIUserAbortError extends AnthropicError {}Common Causes:
stream.abort()Example:
const stream = client.messages.stream({ /* ... */ });
// User decides to cancel
setTimeout(() => stream.abort(), 5000);
try {
await stream.done();
} catch (error) {
if (error instanceof Anthropic.APIUserAbortError) {
console.log('User canceled the request');
}
}try {
const message = await client.messages.create({ /* ... */ });
console.log(message.content);
} catch (error) {
if (error instanceof Anthropic.APIError) {
console.error(`API Error ${error.status}:`, error.message);
} else if (error instanceof Anthropic.APIConnectionError) {
console.error('Connection error:', error.message);
} else {
console.error('Unexpected error:', error);
throw error;
}
}async function createMessage(params: Anthropic.MessageCreateParams) {
try {
return await client.messages.create(params);
} catch (error) {
// HTTP errors
if (error instanceof Anthropic.BadRequestError) {
console.error('Invalid request parameters');
throw new Error('Please check your request parameters');
}
if (error instanceof Anthropic.AuthenticationError) {
console.error('Authentication failed');
throw new Error('Please check your API key');
}
if (error instanceof Anthropic.RateLimitError) {
const retryAfter = error.headers.get('retry-after');
console.error(`Rate limited. Retry after ${retryAfter}s`);
await sleep(parseInt(retryAfter) * 1000);
return createMessage(params); // Retry
}
if (error instanceof Anthropic.InternalServerError) {
console.error('Server error, retrying...');
await sleep(5000);
return createMessage(params); // Retry
}
// Network errors
if (error instanceof Anthropic.APIConnectionTimeoutError) {
console.error('Request timed out');
throw new Error('Request took too long. Try using streaming.');
}
if (error instanceof Anthropic.APIConnectionError) {
console.error('Network error');
throw new Error('Cannot reach Anthropic API. Check your connection.');
}
// User abort
if (error instanceof Anthropic.APIUserAbortError) {
console.log('Request was canceled');
return null;
}
// Unknown error
console.error('Unexpected error:', error);
throw error;
}
}async function retryWithBackoff<T>(
fn: () => Promise<T>,
maxRetries = 3,
initialDelay = 1000
): Promise<T> {
let lastError: Error;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
lastError = error;
// Don't retry on client errors (4xx except 429)
if (
error instanceof Anthropic.BadRequestError ||
error instanceof Anthropic.AuthenticationError ||
error instanceof Anthropic.PermissionDeniedError ||
error instanceof Anthropic.NotFoundError
) {
throw error;
}
// Retry on server errors, network errors, and rate limits
if (
error instanceof Anthropic.RateLimitError ||
error instanceof Anthropic.InternalServerError ||
error instanceof Anthropic.APIConnectionError
) {
const delay = initialDelay * Math.pow(2, attempt);
console.log(`Retry attempt ${attempt + 1} after ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
// Unknown error
throw error;
}
}
throw lastError;
}
// Usage
const message = await retryWithBackoff(() =>
client.messages.create({ /* ... */ })
);try {
const message = await client.messages.create({ /* ... */ });
} catch (error) {
if (error instanceof Anthropic.APIError) {
console.error('Error details:', {
status: error.status,
message: error.message,
requestID: error.requestID, // Include in support requests
timestamp: new Date().toISOString(),
});
// Log for debugging
logger.error('Anthropic API error', {
requestId: error.requestID,
status: error.status,
error: error.error,
});
}
}async function getResponse(prompt: string): Promise<string> {
try {
// Try with Opus first
const message = await client.messages.create({
model: 'claude-opus-4-5-20250514',
max_tokens: 2048,
messages: [{ role: 'user', content: prompt }],
});
return message.content[0].text;
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
console.warn('Opus rate limited, falling back to Sonnet');
// Fall back to Sonnet
const message = await client.messages.create({
model: 'claude-sonnet-4-5-20250929',
max_tokens: 2048,
messages: [{ role: 'user', content: prompt }],
});
return message.content[0].text;
}
throw error;
}
}catch (error) {
if (error instanceof Anthropic.APIError) {
// Status code
console.log(error.status); // 400, 401, 429, etc.
// Error message
console.log(error.message); // Human-readable message
// Request ID
console.log(error.requestID); // 'req_...'
// Response headers
console.log(error.headers.get('x-ratelimit-remaining'));
// Detailed error from API
console.log(error.error); // API error object
// Stack trace
console.log(error.stack);
// Original cause (if wrapped)
console.log(error.cause);
}
}if (error instanceof Anthropic.APIError) {
const apiError = error.error;
console.log('Type:', apiError.type);
console.log('Message:', apiError.message);
// Error-specific fields
if (apiError.type === 'invalid_request_error') {
console.log('Invalid field:', apiError.field);
console.log('Invalid value:', apiError.value);
}
}// ✅ Good: Handle specific errors
try {
const message = await client.messages.create({ /* ... */ });
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
// Handle rate limiting
} else if (error instanceof Anthropic.AuthenticationError) {
// Handle auth issues
} else if (error instanceof Anthropic.APIError) {
// Handle other API errors
} else {
// Handle unexpected errors
}
}
// ❌ Bad: Generic catch-all
try {
const message = await client.messages.create({ /* ... */ });
} catch (error) {
console.error('Error:', error); // Not helpful
}// ✅ Good: Log useful context
try {
const message = await client.messages.create(params);
} catch (error) {
if (error instanceof Anthropic.APIError) {
logger.error('Anthropic API request failed', {
requestId: error.requestID,
status: error.status,
message: error.message,
params: { model: params.model, max_tokens: params.max_tokens },
userId: currentUserId,
});
}
throw error;
}// ✅ Good: User-friendly error messages
try {
const message = await client.messages.create({ /* ... */ });
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
return {
error: 'Too many requests. Please try again in a few moments.',
retryAfter: error.headers.get('retry-after'),
};
} else if (error instanceof Anthropic.APIConnectionError) {
return {
error: 'Unable to connect to service. Please check your internet connection.',
};
} else {
return {
error: 'An unexpected error occurred. Please try again later.',
};
}
}