If you've been building with the Claude API, chances are you've hit at least one of these errors: 429 Too Many Requests, 503 Service Unavailable, or a frustrating timeout that kills your request mid-flight. These errors share a common symptom — the API isn't responding — but each has distinct causes and fixes.
Understanding the Symptoms
429 Too Many Requests (Rate Limit Exceeded)
anthropic.RateLimitError: 429 {"type":"error","error":{"type":"rate_limit_error","message":"Rate limit exceeded. Please retry after X seconds."}}
This error fires when your application exceeds the API's rate limits — either by sending too many requests per minute (RPM), consuming too many tokens per minute (TPM), or hitting the concurrent request ceiling. The response typically includes a retry-after header telling you exactly how long to wait.
503 Service Unavailable (Server Overload)
anthropic.APIStatusError: 503 {"type":"error","error":{"type":"overloaded_error","message":"Anthropic's API is temporarily overloaded."}}
A 503 means Anthropic's servers are temporarily under heavy load. This is usually short-lived — anywhere from a few seconds to a couple of minutes. It's not caused by anything you're doing wrong; it's a capacity issue on the server side.
APIConnectionTimeoutError (Request Timeout)
anthropic.APIConnectionTimeoutError: Request timed out after 600000ms
Your request didn't complete within the allowed time window. This is especially common with large language models when generating long outputs. If your environment has a shorter timeout than the SDK default (600 seconds), you'll see this more often than expected.
Why These Errors Occur
429 — Three Root Causes
① Exceeding RPM (Requests Per Minute) Every Anthropic API tier has an RPM ceiling. Free-tier and Tier 1 accounts have tight limits that can be hit quickly during burst traffic — for example, when multiple users trigger requests simultaneously.
② Exceeding TPM (Tokens Per Minute) Your token budget resets each minute. Long prompts, large outputs, or high-volume batch jobs can drain your TPM allowance before the minute is up, causing 429s even when RPM looks fine.
③ Too Many Concurrent Requests
Running large parallel workloads with Promise.all without rate control is a common culprit. The API enforces a concurrent request limit per account.
503 — Server-Side Issues
503 errors come from Anthropic's infrastructure, not your code. They're caused by peak traffic, rolling deployments, or temporary capacity constraints. Check https://status.anthropic.com/ to see if there's an active incident.
Timeouts — Client-Side Misconfiguration
Timeouts happen when the client gives up before the server responds. The SDK default is 600 seconds, but proxy servers, serverless function limits (e.g., Vercel's 10-second cap on Hobby plans), or custom timeout configurations can cut this short.
Step-by-Step Fixes
Step 1: Identify the Exact Error
Before fixing anything, make sure you're catching and classifying errors properly:
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
try {
const message = await client.messages.create({
model: "claude-opus-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello" }],
});
console.log(message.content);
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
console.error("Rate limit hit:", error.message);
console.error("Retry after:", error.headers?.["retry-after"], "seconds");
} else if (error instanceof Anthropic.APIStatusError) {
console.error("Server error:", error.status, error.message);
} else if (error instanceof Anthropic.APIConnectionTimeoutError) {
console.error("Timeout:", error.message);
} else {
throw error; // re-throw unexpected errors
}
}Step 2: Implement Exponential Backoff with Jitter
Exponential backoff is the single most effective fix for both 429 and 503 errors. The idea: each retry waits twice as long as the previous one, with a small random offset (jitter) to spread out burst retries from multiple clients.
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
/**
* Retries an async function with exponential backoff + jitter
*/
async function withRetry<T>(
fn: () => Promise<T>,
maxRetries = 3,
baseDelay = 1000
): Promise<T> {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
const isRetryable =
error instanceof Anthropic.RateLimitError ||
(error instanceof Anthropic.APIStatusError && error.status === 503) ||
error instanceof Anthropic.APIConnectionTimeoutError;
if (!isRetryable || attempt === maxRetries) {
throw error;
}
// Respect the retry-after header if present
let delay = baseDelay * Math.pow(2, attempt);
if (
error instanceof Anthropic.RateLimitError &&
error.headers?.["retry-after"]
) {
delay = parseInt(error.headers["retry-after"]) * 1000;
}
// Add jitter to avoid thundering herd
const jitter = Math.random() * 500;
const totalDelay = delay + jitter;
console.warn(
`Attempt ${attempt + 1} failed. Retrying in ${Math.round(totalDelay)}ms...`
);
await new Promise((resolve) => setTimeout(resolve, totalDelay));
}
}
throw new Error("Max retries exceeded");
}
// Usage
const response = await withRetry(() =>
client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: "Hello!" }],
})
);
// Expected: Automatically retries on failure, returns response on successTip: The Anthropic SDK has built-in retry support. If you don't need custom logic, use maxRetries directly:
const client = new Anthropic({
maxRetries: 3, // Default is 2
});Step 3: Check and Upgrade Your Rate Limit Tier
Visit https://console.anthropic.com/settings/limits to see your current Tier and limits.
Approximate Tier limits (as of April 2026):
- Free: 5 RPM / 25,000 TPM
- Tier 1: 50 RPM / 50,000 TPM (after first $5 deposit)
- Tier 2: 1,000 RPM / 400,000 TPM (after $500 in usage)
- Tier 3: 2,000 RPM / 800,000 TPM (after $5,000 in usage)
Tier upgrades happen automatically as your usage grows. For enterprise-level limits, contact Anthropic directly.
Step 4: Add Concurrency Control for Parallel Requests
If you're sending many requests in parallel, use a queue to cap concurrency:
import Anthropic from "@anthropic-ai/sdk";
import PQueue from "p-queue"; // npm install p-queue
const client = new Anthropic();
// Max 5 concurrent requests, max 10 per second
const queue = new PQueue({
concurrency: 5,
intervalCap: 10,
interval: 1000,
});
const prompts = [
"Explain quantum computing",
"What is machine learning?",
"History of the internet",
// ... many more prompts
];
const results = await Promise.all(
prompts.map((prompt) =>
queue.add(() =>
client.messages.create({
model: "claude-haiku-4-5-20251001",
max_tokens: 512,
messages: [{ role: "user", content: prompt }],
})
)
)
);
// Expected: All requests complete without triggering rate limitsStep 5: Fix Timeout Issues
For long-running generations, extend the timeout configuration:
// Client-level timeout
const client = new Anthropic({
timeout: 120 * 1000, // 120 seconds
});
// Per-request timeout (SDK v0.30.0+)
const response = await client.messages.create(
{
model: "claude-opus-4-6",
max_tokens: 4096,
messages: [{ role: "user", content: "Write a detailed technical report" }],
},
{
timeout: 180 * 1000, // 180 seconds for this request only
}
);For long outputs, streaming is often a better solution than increasing timeout values:
const stream = await client.messages.stream({
model: "claude-sonnet-4-6",
max_tokens: 4096,
messages: [{ role: "user", content: "Write a detailed technical spec" }],
});
for await (const chunk of stream) {
if (
chunk.type === "content_block_delta" &&
chunk.delta.type === "text_delta"
) {
process.stdout.write(chunk.delta.text);
}
}
// Expected: Text streams in real-time, timeout risk is eliminatedVerifying the Fix
Once you've applied your changes, confirm everything is working:
-
Monitor error logs: 429s should be handled by retries and no longer bubble up as unhandled exceptions.
-
Check Usage in Console: Visit
https://console.anthropic.com/settings/usageand verify RPM/TPM usage stays comfortably below your tier ceiling. -
Measure response time:
const start = Date.now();
const response = await client.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 1024,
messages: [{ role: "user", content: "Test" }],
});
const elapsed = Date.now() - start;
console.log(`Response time: ${elapsed}ms`);
// Expected output: Response time: 1800ms (will vary)- Check Anthropic Status: If 503s persist, check
https://status.anthropic.com/for active incidents.
Prevention: Long-Term Best Practices
Use SDK Built-in Retries as Your First Line of Defense
Before writing custom retry logic, set maxRetries on your SDK client. It handles the most common cases out of the box.
Estimate Token Usage Before Sending
Use Anthropic's Tokenizer or a lightweight estimation function to predict token consumption before sending batches.
function estimateTokens(text: string): number {
// Rough estimate: ~4 chars per token for English
return Math.ceil(text.length / 4);
}
const prompt = "Explain the concept of neural networks";
console.log(`Estimated tokens: ${estimateTokens(prompt)}`);
// Expected output: Estimated tokens: 10Schedule Batch Jobs During Off-Peak Hours
If you're running large batch workloads, schedule them during nights or weekends when API traffic is lower and you have more headroom before hitting limits.
Set Up Error Monitoring and Alerts
In production, integrate with Sentry, Datadog, or your preferred monitoring platform. Alert when 429/503 error rates exceed a threshold — catching the problem early is far cheaper than debugging it after customers complain.
Looking back
Claude API errors — 429, 503, and timeouts — are manageable with the right patterns in place. Here's the quick-reference summary:
- 429 (Rate Limited): Use exponential backoff with jitter, respect
retry-afterheaders, control concurrency with a queue, and upgrade your Tier if needed. - 503 (Server Overload): Same backoff strategy applies; check status.anthropic.com for incident updates.
- Timeouts: Extend client timeout settings, use streaming for long outputs, and check for serverless platform limits.
The Anthropic SDK's built-in maxRetries option covers most cases. Layer in custom backoff and concurrency control for production workloads where reliability matters.