Claude API 429 rate_limit_error: 원인과 해결법 (2026)
Claude API 429 rate_limit_error는 조직의 분당/일별 요청수(RPM/RPD) 또는 토큰수(TPM/TPD)가 한도 초과에 발생합니다. Rate limit 초과이며, exponential backoff 재시도가 효과적해야 합니다. 이 글은 5가지 흔한 원인과 Python/TypeScript 코드 예시를 다룹니다.
전반적인 Claude API 에러 처리 패턴은 Claude API Error Handling 가이드를 참고하세요.
무엇을 의미하는가?
429 HTTP 상태 코드는 조직의 분당/일별 요청수(RPM/RPD) 또는 토큰수(TPM/TPD)가 한도 초과을 의미합니다. Anthropic API의 에러 응답 본문에는 error.type이 "rate_limit_error"로 명시되며, error.message에 구체적 사유가 옵니다.
응답 예시:
{
"type": "error",
"error": {
"type": "rate_limit_error",
"message": "..."
}
}
흔한 원인 5가지
- 분당 요청수(RPM) 초과 — 첫 tier는 보통 50 RPM
- 분당 토큰수(TPM) 초과 — 첫 tier는 50,000 TPM
- 단일 burst로 한 번에 100건+ 요청 시도
- Batch API 미사용 (batch는 별도 quota)
해결 코드 (Python)
import time, anthropic
def with_backoff(fn, max_retries=5):
for attempt in range(max_retries):
try:
return fn()
except anthropic.RateLimitError as e:
if attempt == max_retries - 1:
raise
wait = 2 ** attempt # 1, 2, 4, 8, 16
# Honor Retry-After header if present
retry_after = e.response.headers.get("retry-after")
if retry_after:
wait = max(wait, int(retry_after))
print(f"Rate limited. Waiting {wait}s (attempt {attempt+1})")
time.sleep(wait)
해결 코드 (TypeScript)
async function withBackoff<T>(fn: () => Promise<T>, maxRetries = 5): Promise<T> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (e: any) {
if (!(e instanceof Anthropic.RateLimitError) || attempt === maxRetries - 1) {
throw e;
}
let wait = Math.pow(2, attempt) * 1000;
const retryAfter = e.headers?.["retry-after"];
if (retryAfter) wait = Math.max(wait, Number(retryAfter) * 1000);
console.log(`Rate limited. Waiting ${wait}ms`);
await new Promise((r) => setTimeout(r, wait));
}
}
throw new Error("max retries exceeded");
}
Tier별 Rate Limit 한도표 (2026)
| Tier | RPM | TPM | 조건 |
|---|---|---|---|
| Tier 1 | 50 | 50,000 | 신규 계정 |
| Tier 2 | 1,000 | 160,000 | $40 이상 충전 |
| Tier 3 | 2,000 | 320,000 | $200 이상 사용 |
| Tier 4 | 4,000 | 400,000 | $1,000 이상 사용 |
Tier 1의 50 RPM 기준으로, 분당 50건을 초과하는 순간 429가 발생합니다. 병렬 처리 수(concurrency)를 RPM / 60으로 설정해 초당 요청 수를 제한하는 것이 기본 전략입니다.
Batch API를 활용한 quota 절약: 비실시간 작업(문서 분석, 배치 번역, 대량 분류 등)은 Message Batches API를 사용하면 동일 모델에 대해 별도 quota를 사용하므로 실시간 API의 rate limit 소진을 줄일 수 있습니다.
재시도 전략
이 에러는 재시도 가능합니다. Exponential backoff 권장 시퀀스:
attempt 1 → wait 1s
attempt 2 → wait 2s
attempt 3 → wait 4s
attempt 4 → wait 8s
attempt 5 → wait 16s (final)
응답 헤더의 retry-after가 있으면 그 값을 우선 사용하세요.
비용 영향
재시도 시 매번 input 토큰이 다시 청구됩니다. 재시도 횟수 × 입력 토큰 = 추가 비용. Prompt caching을 적용하면 재시도 비용을 90%까지 절감할 수 있습니다.
자세한 비용 절감 패턴은 Claude API Cost and Prompt Caching Break-Even 또는 무료 비용 계산기를 참고하세요.
빠른 진단 체크리스트
Rate limit 충돌 원인을 빠르게 파악하는 체크리스트:
- 응답 헤더
x-ratelimit-remaining-requests값이 0 또는 음수인가? - 응답 헤더
x-ratelimit-remaining-tokens를 확인해 TPM 초과인지 RPM 초과인지 구분했는가? -
x-ratelimit-reset-requests(초 단위) 헤더를 읽어 정확한 대기 시간을 계산하고 있는가? - 동시 요청(concurrency)이 Tier별 RPM을 초과하지 않도록 세마포어 또는 큐를 사용하고 있는가?
- 비실시간 배치 작업을 Batch API로 전환했는가? (별도 quota)
프로덕션 모니터링
Rate limit 헤더를 파싱해 실시간 사용량을 추적하면 한도 도달 전에 스로틀링을 걸 수 있습니다:
import anthropic, logging, time
logger = logging.getLogger("claude.ratelimit")
def tracked_request(client: anthropic.Anthropic, **kwargs):
response = client.messages.create(**kwargs)
# Python SDK는 raw_response를 통해 헤더에 접근 가능
# 실제 구현 시 httpx response headers를 직접 파싱하거나
# with_raw_response 방식 사용
return response
def handle_rate_limit(exc: anthropic.RateLimitError, attempt: int) -> float:
"""헤더 기반 대기 시간 계산."""
retry_after = exc.response.headers.get("retry-after")
x_reset = exc.response.headers.get("x-ratelimit-reset-requests")
remaining = exc.response.headers.get("x-ratelimit-remaining-requests", "?")
logger.warning(
"429 rate_limit_error",
extra={
"attempt": attempt,
"remaining_requests": remaining,
"retry_after": retry_after,
"reset_in": x_reset,
}
)
# 헤더 값 우선, 없으면 지수 백오프
if retry_after:
return float(retry_after)
return min(2 ** attempt, 60)
x-ratelimit-remaining-tokens가 전체 TPM의 20% 미만으로 떨어지면 알림을 발송해 Tier 업그레이드 시점을 파악하세요.
언제 지원팀에 연락해야 하나요?
대부분의 429는 백오프 로직으로 해결됩니다. 아래 경우에만 support.anthropic.com에 문의하세요:
- Tier 4 이상인데도 매일 RPM 한도에 도달해 비즈니스에 영향이 있는 경우 (Tier 업그레이드 요청)
-
x-ratelimit-reset-requests헤더가 없거나 비정상적으로 긴 값(3600초 이상)을 반환하는 경우 - 실제 요청 수가 Tier 한도보다 훨씬 적은데도 429가 반환되는 경우 (집계 버그 가능성)
관련 에러
- 400 invalid_request_error — 잘못된 요청 형식
- 401 authentication_error — 인증 실패
- 403 permission_error — 권한 부족
- 429 rate_limit_error — Rate limit 초과
- 529 overloaded_error — API 일시 과부하
자주 묻는 질문
429 에러가 떴을 때 비용이 청구되나요?
처리되지 않은 요청은 청구되지 않습니다. 단, 재시도 후 성공한 요청은 정상 청구됩니다.
429와 다른 에러의 차이는?
429는 일시적/서버 측 이슈로 재시도가 효과적입니다. 반면 4xx 클라이언트 에러 (400/401/403/404)는 요청 자체에 문제가 있어 재시도해도 동일한 결과가 나옵니다.
Bedrock/Vertex에서도 같은 에러 코드인가요?
네, Anthropic의 error.type 명명 규칙은 모든 deployment (Direct API, AWS Bedrock, GCP Vertex AI)에서 동일합니다. 다만 HTTP 상태 코드는 platform 별로 wrapping되어 다를 수 있습니다 (예: Bedrock은 429을 ValidationException으로 wrap).
다음 단계
- 프로덕션 코드에 retry 로직을 추가하려면 Production Patterns for Claude Agents를
- 비용을 모니터링하려면 Claude API 비용 모니터링 가이드를
- 에러 분류 자동화는 무료 /cheatsheet-한국어에서 30개 프롬프트로
에러 처리 패턴 30개 + Pydantic 검증 코드 — Claude API Cost Optimization 마스터클래스 ($59)에 retry 미들웨어, 비용 가드레일, 에러 알림 패턴 12편 포함.