CATEGORY

카테고리 (689)
AI (87)
Language & Specs (260)
FrameWork (36)
Library (20)
App (41)
Git (10)
Build & Dependency (2)
AWS (15)
DataBase (45)
OS (33)
Tool (17)
IT (120)
SEEMINGLY ONLINE

Seemingly
Online

이모저모 방방곡곡 두루두루 개발지식 저장소

RECENT POSTS

AI/Claude

claude api 429 에러 — rate limit과 529 해결

반응형

Claude API의 429 에러(rate_limit_error)는 조직의 분당 한도(요청 수·입력 토큰·출력 토큰) 중 하나를 넘었거나, 등급의 월 지출 상한에 닿았다는 뜻입니다. 529(overloaded_error)는 내 사용량과 상관없이 API 전체가 붐빌 때 납니다. 파이썬 SDK는 둘 다 알아서 2번 더 재시도한 뒤에야 RateLimitError·OverloadedError를 던집니다. 그래서 할 일은 세 가지입니다: retry-after 헤더만큼 기다리기, 월 상한 429를 따로 가려내기, 응답 헤더로 남은 한도 보기. 아래는 2026년 10월 23일 공식 문서와 anthropic 파이썬 SDK 2.1.0 기준입니다.

1. claude api 429 에러와 529 차이

둘 다 "나중에 다시 하라"는 에러지만 원인이 다르고, 그래서 대처도 다릅니다. 공식 Errors 문서의 정의를 정리하면 이렇습니다.

코드 원인 파이썬 예외 대처
429 rate_limit_error 내 조직이 RPM·ITPM·OTPM 한도를 넘음, 사용량이 갑자기 늘어 걸린 acceleration limit anthropic.RateLimitError retry-after초 기다린 뒤 재시도, 요청량·토큰 줄이기
429 (월 지출 상한) 등급의 월 지출 상한 도달. retry-after 없음 anthropic.RateLimitError (같음) 재시도 무의미. 다음 달 1일 00:00 UTC까지 막히거나 등급 상향
529 overloaded_error 모든 사용자의 트래픽이 몰려 API가 일시적으로 과부하 anthropic.OverloadedError 내 코드 문제 아님. 간격을 늘려 재시도

한도는 API 키가 아니라 조직 단위로 걸립니다. 키를 여러 개 만들어 나눠 써도 한도는 늘지 않습니다. 또 한도는 토큰 버킷 방식이라 1분 동안 고르게 쓰지 않으면 더 짧은 구간에서도 걸립니다. 문서의 예로는 60 RPM이 초당 1건으로 적용될 수 있어서, 한꺼번에 몰아 보낸 요청은 분당 평균이 한도 안이어도 429가 납니다.

Claude Code(CLI)를 쓰다 429·529를 만났다면 원인 확인 방법이 다릅니다. 그쪽은 클로드 코드 api 에러 글에 따로 정리했습니다. 이 글은 API를 코드로 직접 부르는 경우입니다.

2. claude api rate limit 한도 — 무엇이 세어지나

Messages API 한도는 모델별로 RPM(분당 요청 수)·ITPM(분당 입력 토큰)·OTPM(분당 출력 토큰) 세 가지입니다. 이 중 하나만 넘어도 429입니다. 공식 문서의 Start 등급 기본값은 Claude Sonnet 5.5 기준 1,000 RPM, 2,000,000 ITPM, 400,000 OTPM입니다. 조직의 등급과 실제 한도는 콘솔의 Rate limits 페이지(platform.claude.com/usage/limits)에서 봅니다. 새 조직은 이보다 낮은 Evaluation 등급에서 시작할 수 있고, 사용 이력이 쌓이면 자동으로 올라갑니다.

세는 방식에서 알아 둘 점이 두 가지 있습니다.

  • 캐시에서 읽은 입력은 ITPM에 안 들어갑니다(대부분의 모델). ITPM에 세어지는 건 input_tokens와 cache_creation_input_tokens뿐입니다. 공식 문서 예로, 2,000,000 ITPM에서 캐시 적중률이 80%면 분당 10,000,000 입력 토큰까지 처리할 수 있습니다. 그래서 ITPM 429가 잦으면 한도 상향보다 프롬프트 캐싱 클로드 설정이 먼저입니다.
  • max_tokens는 OTPM 계산에 안 들어갑니다. OTPM은 실제로 생성된 토큰만 셉니다. max_tokens를 크게 잡았다고 429가 더 나지는 않습니다.

월 지출 상한은 따로 있습니다. Start 등급 $500, Build $1,000, Scale $200,000입니다. 여기에 닿으면 한도 초과와 똑같은 429 rate_limit_error가 오는데, 기다려도 풀리지 않습니다. 콘솔에서 내가 직접 정한 지출 한도에 닿은 경우는 429가 아니라 400 invalid_request_error로 옵니다. 모델별 토큰 단가는 클로드 api 가격 글에 있습니다.

3. anthropic RateLimitError 잡기 — SDK는 이미 2번 재시도했다

공식 파이썬 SDK는 429와 5xx(529 포함)를 받으면 기본 2번 자동 재시도합니다. retry-after 헤더가 있으면 그만큼 기다리고, 없으면 0.5초부터 두 배씩 늘리는 지수 백오프(최대 8초)를 씁니다. 그래서 예외가 내 코드까지 올라왔다면 이미 요청이 3번 실패한 뒤입니다.

import anthropic

client = anthropic.Anthropic()  # max_retries 기본값 2

try:
    message = client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": "안녕"}],
    )
    print(message.content[0].text)
except anthropic.RateLimitError as e:
    print("429:", e.request_id)
    print("retry-after:", e.response.headers.get("retry-after"))
except anthropic.OverloadedError as e:
    print("529:", e.request_id)

가짜 서버로 공식 문서의 에러 응답 모양을 돌려주고 이 코드를 그대로 실행했습니다(실제 API 키는 쓰지 않았습니다). 429를 계속 돌려주면 요청이 3번 나가고, 그사이 SDK는 retry-after: 2를 따라 2초씩 두 번 기다린 뒤 예외를 던졌습니다.

429: req_011CTest429
retry-after: 2

첫 요청만 429이고 두 번째에 성공하는 경우는 예외 없이 답이 그대로 출력됐습니다. 즉 잠깐 걸리는 429는 SDK가 조용히 넘겨 주고, 코드에는 "가끔 느린 요청"으로만 보입니다. 재시도가 일어나는지 보고 싶으면 환경 변수 ANTHROPIC_LOG=info를 켜고 실행합니다. 재시도할 때마다 이런 로그가 찍힙니다.

INFO] HTTP Request: POST https://api.anthropic.com/v1/messages "HTTP/1.1 429 Too Many Requests"
INFO] Retrying request to /v1/messages in 2.000000 seconds

e.request_id는 응답 헤더 request-id 값입니다. 계속 실패해서 지원팀에 문의할 때 이 값을 같이 보내면 됩니다. 에러 메시지 문자열로 분기하지 말고 예외 클래스로 잡으라는 것이 공식 문서의 권장입니다.

⚠️ SDK는 retry-after를 상한 없이 그대로 따릅니다. 2.1.0 소스(_calculate_retry_timeout)는 헤더 값이 양수면 그 초를 그대로 기다립니다. 가짜 서버가 retry-after: 900을 주자 SDK는 900초씩 두 번, 합쳐 30분을 기다리려 했습니다. 웹 요청 안에서 Claude를 부르는 서버라면 사용자 쪽에서는 그냥 멈춘 것처럼 보입니다. 오래 기다릴 수 없는 곳이라면 5번처럼 재시도를 직접 관리합니다.

4. 월 지출 상한 429 구분하기 — enforced_spend_limit_reached

월 상한에 닿았을 때의 429는 예외 클래스가 일반 429와 똑같은 RateLimitError입니다. 차이는 응답 본문에 있습니다. 공식 문서 기준으로 Messages API는 error.details.error_code에 enforced_spend_limit_reached를 넣어 주고, retry-after 헤더는 없습니다.

import anthropic

client = anthropic.Anthropic()

try:
    message = client.messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": "안녕"}],
    )
except anthropic.RateLimitError as e:
    error = e.body.get("error", {}) if isinstance(e.body, dict) else {}
    code = (error.get("details") or {}).get("error_code")
    if code == "enforced_spend_limit_reached":
        print("월 지출 한도 도달 - 재시도해도 안 풀림")
        print(error.get("message"))
    else:
        print("요청량 초과 - retry-after:", e.response.headers.get("retry-after"))

두 가지 응답을 각각 돌려준 결과입니다.

# 일반 429
요청량 초과 - retry-after: 2

# 월 상한 429
월 지출 한도 도달 - 재시도해도 안 풀림
You have reached your API usage limits: your organization has crossed its monthly API usage threshold, set based on your organization's API tier. You will regain access on 2026-11-01 at 00:00 UTC.

주의할 점은 SDK가 이 429도 똑같이 2번 재시도한다는 것입니다. 실행해 보니 retry-after가 없어서 약 0.4초, 0.9초를 기다리며 요청이 3번 나간 뒤에 예외가 왔습니다. 풀릴 수 없는 에러에 헛요청을 두 번 더 보내는 셈입니다. 메시지에 접근이 돌아오는 시각이 들어 있으니, 사용자에게 보여 줄 문구는 이 메시지에서 가져오면 됩니다. 등급을 올리면 바로 풀리고, 상향 요청은 콘솔 Rate limits 페이지의 Request tier increase로 합니다.

5. 재시도 횟수 바꾸기와 직접 재시도

재시도 횟수는 클라이언트를 만들 때 max_retries로 정하고, 호출 하나만 바꾸려면 with_options()를 씁니다.

import anthropic

client = anthropic.Anthropic(max_retries=5)  # 클라이언트 전체

try:
    # 이 호출만 재시도 끄기
    client.with_options(max_retries=0).messages.create(
        model="claude-sonnet-5-5",
        max_tokens=1024,
        messages=[{"role": "user", "content": "안녕"}],
    )
except anthropic.RateLimitError as e:
    print("바로 실패:", e.status_code)

max_retries=0이면 요청이 1번만 나가고 곧바로 바로 실패: 429가 찍혔습니다. 이렇게 SDK 재시도를 끄고 직접 관리하면, 3번에서 본 긴 retry-after에 대기 상한을 걸 수 있습니다.

import time
import anthropic

client = anthropic.Anthropic(max_retries=0)  # 재시도는 직접 한다

def create_with_retry(attempts=4, max_wait=60, **kwargs):
    for i in range(attempts):
        try:
            return client.messages.create(**kwargs)
        except (anthropic.RateLimitError, anthropic.OverloadedError) as e:
            if i == attempts - 1:
                raise
            wait = float(e.response.headers.get("retry-after") or 2 ** i)
            if wait > max_wait:
                raise  # 너무 오래 기다려야 하면 바로 포기
            print(f"{e.status_code} -> {wait}초 뒤 재시도")
            time.sleep(wait)

message = create_with_retry(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "안녕"}],
)
print(message.content[0].text)

세 가지 상황으로 돌려 봤습니다. 429가 한 번 나면 retry-after를 따라 2초 뒤 성공했고, retry-after: 900이면 기다리지 않고 첫 실패에서 바로 예외를 올렸습니다. 529가 계속되면 1·2·4초 간격으로 기다리다 네 번째 실패에서 예외를 올렸습니다.

# 429 한 번 뒤 성공
429 -> 2.0초 뒤 재시도
안녕하세요!

# 529 계속
529 -> 1.0초 뒤 재시도
529 -> 2.0초 뒤 재시도
529 -> 4.0초 뒤 재시도
anthropic.OverloadedError: Error code: 529 - ...

월 상한 429까지 걸러 내려면 4번의 error_code 확인을 except 안 맨 앞에 넣어 곧바로 raise하게 하면 됩니다. 반대로 서버가 응답 헤더 x-should-retry: false를 주면 SDK는 횟수가 남아 있어도 재시도하지 않습니다(실행해 보니 요청 1번).

6. 응답 헤더로 남은 한도 보기 — anthropic-ratelimit

429가 나기 전에 여유를 보고 싶으면 성공한 응답의 헤더를 읽습니다. API는 매 응답에 anthropic-ratelimit-* 헤더로 한도·남은 양·다시 차는 시각을 실어 보냅니다. 파이썬 SDK에서는 with_raw_response로 호출해야 헤더가 보입니다.

import anthropic

client = anthropic.Anthropic()

raw = client.messages.with_raw_response.create(
    model="claude-sonnet-5-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "안녕"}],
)
for name in (
    "anthropic-ratelimit-requests-remaining",
    "anthropic-ratelimit-input-tokens-remaining",
    "anthropic-ratelimit-output-tokens-remaining",
    "anthropic-ratelimit-input-tokens-reset",
):
    print(name, "=", raw.headers.get(name))

message = raw.parse()  # 평소처럼 Message 객체
print(message.content[0].text)
anthropic-ratelimit-requests-remaining = 49
anthropic-ratelimit-input-tokens-remaining = 48000
anthropic-ratelimit-output-tokens-remaining = 8000
anthropic-ratelimit-input-tokens-reset = 2026-10-23T08:01:00Z
안녕하세요!

(값은 가짜 서버가 넣은 것입니다.) 공식 문서 기준으로 *-remaining의 토큰 수는 천 단위로 반올림되고, *-reset은 RFC 3339 형식의 시각입니다. 다만 토큰 버킷이라 이 시각까지 기다려야 하는 건 아니고, 그때 완전히 다시 찬다는 뜻입니다. anthropic-ratelimit-tokens-* 헤더는 지금 걸려 있는 가장 빡빡한 한도(예: 워크스페이스 한도) 기준으로 나옵니다.

자주 묻는 질문 (FAQ)

Q. claude api rate limit을 올리려면 어떻게 하나요?
콘솔의 Rate limits 페이지에서 Request tier increase로 요청합니다. Claude 고객지원 문서 기준으로 현재 한도의 50% 이상을 쓰고 있어야 상향을 요청할 수 있습니다. Scale 등급보다 높은 한도가 필요하면 같은 페이지에서 영업팀에 문의하는 Custom 등급으로 갑니다.

Q. 대량 요청을 돌리면 429가 계속 납니다.
바로 답이 필요 없는 작업이면 claude batch api로 돌리는 편이 낫습니다. Message Batches API는 Messages API와 별도의 한도를 쓰고 요금도 50% 할인됩니다. 실시간으로 꼭 보내야 한다면 공식 문서 권장대로 트래픽을 한 번에 올리지 말고 서서히 늘립니다. 갑자기 늘리면 분당 한도 안이어도 acceleration limit 429가 납니다.

Q. 스트리밍 중에 과부하가 나면 OverloadedError로 잡히나요?
아닙니다. 스트리밍은 HTTP 200으로 시작한 뒤 본문 안에서 error 이벤트가 오기 때문에, 상태 코드로 클래스를 고를 수 없어 APIStatusError로 옵니다. 처리 방법은 claude api streaming 글의 5번에 있습니다.

Q. OpenAI·Gemini의 429와 뭐가 다른가요?
세 곳 모두 429를 쓰지만, 크레딧 소진·일일 한도 같은 다른 원인이 같은 코드로 오는 방식이 제각각입니다. openai api 429 에러와 gemini api 429 에러 글에 각각 정리했습니다.

마무리

정리하면 claude api 429는 조직 단위 분당 한도나 월 지출 상한, 529는 API 전체 과부하입니다. 파이썬 SDK는 둘 다 기본 2번 재시도한 뒤에 예외를 던집니다. 놓치기 쉬운 곳은 세 가지입니다. 월 상한 429는 details.error_code로만 구분되는데 SDK가 이것까지 헛재시도하고, retry-after는 상한 없이 그대로 기다리며, ITPM 429는 한도 상향보다 프롬프트 캐싱으로 먼저 줄일 수 있다는 점입니다.


📚 참고 출처 (2026년 10월 23일 확인 · anthropic 파이썬 SDK 2.1.0)
· Rate limits — Claude API Docs
· Claude API errors — Claude API Docs
· 429 errors and rate limits — Claude Help Center

반응형

COMMENTS