Claude Code는 API 키에 대해서는 rate-limit 에러를 재시도하지만, Max 플랜에 대해서는 그렇지 않습니다
요약
Claude Code 디컴파일 분석 결과, API 키와 달리 Pro/Max 구독 사용자는 429 Rate-limit 에러 발생 시 자동 재시도가 작동하지 않고 세션이 즉시 종료되는 현상을 확인했습니다.
핵심 포인트
- Claude Code는 결제 방식에 따라 429 에러 재시도 여부를 결정함
- API 키 및 Enterprise 계정은 429 에러 시 재시도를 수행함
- Pro/Max 구독 사용자는 429 에러 발생 시 재시도 없이 세션이 종료됨
- 이는 SDK의 기본 동작이 아닌 Claude Code 클라이언트 측의 의도적인 구현임
Max 플랜에서 에이전트가 길게 실행되던 중, 단 한 번의 429 에러로 모든 것이 종료됩니다. 일시 정지되는 것이 아닙니다. 종료됩니다. 턴(turn)이 죽고, 진행 중이던 작업은 사라지며, 백오프(backoff), 재시도(retry), 카운트다운도 없습니다. API 키를 사용했다면 동일한 에러, 정확히 똑같은 HTTP 429 에러가 발생했더라도 조용히 재시도되었을 것이고 당신은 이를 전혀 인지하지 못했을 것입니다.
이유를 알고 싶어서 Claude Code 바이너리(버전 2.1.179)를 디컴파일하여 재시도 경로(retry path)를 읽어보았습니다. 답은 단 하나의 분기(branch)였으며, 이는 당신이 어떻게 결제하느냐에 따라 결정됩니다.
결제 방식에 따라 결정되는 단 하나의 분기
Claude Code는 모든 모델 요청을 재시도 분류기(retry classifier)로 감쌉니다. 디컴파일된 결과, rate-limit 결정은 단 한 줄로 요약됩니다:
if (status === 429) return !kq() || GsH()
kq()와 GsH()는 난독화(minified)된 이름입니다. 각 게이트가 무엇을 확인하는지 읽기 쉬운 이름으로 바꾼 동일한 분기는 다음과 같습니다:
if (status === 429) return !isConsumerSubscription() || isEnterprise()
isConsumerSubscription()은 소비자 구독(consumer subscription)으로 인증할 때 true가 됩니다. 즉, Pro 및 Max 로그인이 갖는 user:inference 스코프(scope)를 OAuth 토큰이 보유하고 있는 경우입니다. isEnterprise()는 Enterprise 계정인 경우에만 true가 됩니다. 이를 읽어보면 다음과 같습니다:
- API 키 -
isConsumerSubscription()false - 429 재시도 가능. - Enterprise -
isEnterprise()true - 429 재시도 가능. - Pro / Max -
isConsumerSubscription()true,isEnterprise()false -!true || false는 false - 429 재시도 불가능.
분류기가 재시도 불가능(non-retryable)을 반환하면 요청은 예외를 던집니다(throws). 구독 모델에서는 그 예외가 곧 당신의 세션 종료를 의미합니다.
상황은 더 명확해집니다. Anthropic의 용량 초과 신호인 529 "overloaded" 에러는 계층(tier) 확인 없이 모든 사용자에게 재시도됩니다. 즉, status >= 500은 조건 없이 재시도 가능(retryable)한 것으로 반환됩니다. 따라서 차이점은 "구독 모델이 재시도를 덜 받는다"가 아닙니다. 구체적으로는 429 rate-limit 에러에 한정되며, 오직 정액제 계층(flat-rate tiers)에서만 발생합니다. 그리고 Anthropic의 공식 SDK는 기본적으로 429 에러에 대해 지수 백오프(exponential backoff)를 적용하여 두 번의 재시도를 수행합니다. Claude Code는 이를 꺼버립니다. SDK 클라이언트에 maxRetries: 0을 전달하고, 구독 분기(subscription branch)를 별도로 붙여 재시도 로직을 직접 구현합니다. 이것은 SDK의 동작이 새어 나온 것이 아니라, 클라이언트 측의 결정입니다.
방어 논리, 그리고 그 한계
해당 분기에는 타당한 방어 논리가 있으며, 이는 제대로 구현될 가치가 있습니다. 구독 모델에서의 429 에러는 종종 사용량 윈도우(usage-window) 제한인 경우가 많습니다. 즉, 5시간 할당량을 모두 소진했으며, 몇 분에서 몇 시간 동안은 초기화되지 않는 상황입니다. 이 상황에서 프로세스 내에서 재시도를 하는 것은 무의미합니다. 더 나아가, 자신의 할당량 상한선을 계속 두드리는 클라이언트는 잘못된 동작을 하는 것이며, 벤더(vendor)가 이를 배포하지 않는 것은 정당합니다. 만약 모든 Max 클라이언트가 사용량 윈도우 429 에러를 타이트한 루프(tight loop)로 재시도한다면, 그 제한은 아무런 의미가 없게 될 것입니다. 이 모든 말은 사실입니다. 윈도우 할당량(window-quota) 케이스의 경우, 재시도하지 않는 것이 올바른 결정입니다.
그렇다면 해당 분기가 실제로 무엇을 하는지 살펴보십시오. 이 분기는 두 종류의 429를 구분하지 않습니다. Anthropic의 제한은 두 가지 형태입니다: 긴 사용량 윈도우(usage window), 그리고 짧은 분당 요청 및 토큰 상한선(per-minute request and token ceilings)입니다. 분당 제한은 몇 초 내에 해제됩니다. 이는 백오프(backoff)의 교과서적인 사례입니다. 2초를 기다렸다가 재시도하면 성공합니다. 하지만 분류기(classifier)는 status === 429는 곧 status === 429이기 때문에 두 가지를 동일하게 취급합니다. 윈도우 할당량 케이스에 대한 타당한 논리가, 결과적으로는 아주 쉽게 재시도 가능한 분당 제한 케이스까지 죽여버리는 예외를 정당화하게 됩니다. 분당 제한은 백오프가 정답인 정확한 사례이며, 다른 모든 계층은 이를 무료로 누리고 있는 기능입니다.
이것이 바로 가장 강력한 논리로 반박했을 때(steelman) 버티지 못하는 지점입니다. 종량제 계층(metered tiers)은 분당 429 에러를 재시도하여 복구합니다. 정액제 계층(flat-rate tier)은 이를 세션 종료로 받아들입니다.
동기가 아닌 메커니즘
저는 동기가 아닌 메커니즘을 보여드리고 있는 것입니다. 저는 바이너리(binary) 내의 한 분기(branch)를 읽었습니다. 이것이 의도적인 계층화(tiering)인지, 범위를 벗어난 보수적인 기본 설정인지, 아니면 아무도 다시 검토하지 않은 실수인지 저는 말씀드릴 수 없습니다. 동일한 증거를 바탕으로 어느 쪽이라고 주장하는 사람은 추측을 하는 것입니다. 제가 여기서 왜 신중한지에 대해 솔직하게 말씀드리겠습니다. 저는 지난 6월 15일에 이 동일한 벤더(vendor)에 대한 분석(teardown)을 게시했다가 바로 다음 날 수정했습니다. 증거가 뒷받침하지 않는 의도(intent)를 단정 지었기 때문입니다. 한 번은 교훈이지만, 두 번은 제가 시작하고 싶지 않은 패턴이 됩니다.
증거가 보여주는 것은 바로 **결과(effect)**입니다. 현재 이 클라이언트에서, 정액제 계층(flat-rate tier)은 종량제(metered) 계층보다 덜 관대한 에러 경로(error path)로 실행됩니다. 설계에 의한 것이든 방치에 의한 것이든, 매월 고정된 가격을 지불하는 사람들은 토큰당 비용을 지불하는 사람들이 겪지 않는 실패를 감수하고 있습니다.
신뢰성(Reliability)은 가격 페이지에 있지 않습니다
신뢰성은 당신이 구매하는 것의 일부이며, 가격 페이지에는 나와 있지 않습니다. 당신은 가격과 할당량(quota)에 따라 도구 계층을 선택하며, 그 아래의 실패 처리(failure handling) 방식은 동일할 것이라고—즉, 한도(limits)만 이동할 뿐이라고—가정합니다. 여기 그 가정이 깨지는 구체적인 사례가 있습니다. 재시도 동작(retry behavior) 자체가 당신의 결제 관계에 따라, 디컴파일(decompile)하지 않는 한 절대 볼 수 없는 분기(branch) 내에서 조용히 변합니다.
만약 당신이 구독 계층(subscription tier)에서 에이전트 워크플로우(agentic workflows)를 구축하고, 그것들이 일시적인 제한(transient limits)을 견뎌낼 것이라고 믿고 있다면, 그 신뢰는 하중을 지탱하고 있지만 테스트되지 않은 상태입니다. 할당량 계산이 적절하다는 이유로 팀을 위해 Max 플랜을 선택한 스태프 엔지니어(staff engineer)는, 자신도 모르게 2초간의 회복 가능한 일시적 오류를 실패한 실행으로 바꿔버리는 계층을 선택한 것입니다.
이것은 하나의 바이너리 버전인 2.1.179, 2026년 6월 기준이며, 향후 릴리스에서 해당 분기를 다시 작성하여 이 발견 사항을 폐기할 수도 있습니다. 이를 인용할 때는 버전을 명시하십시오. 구독 대 종량제(subscription-versus-metered)의 분리는 위에서 언급한 윈도우 할당량(window-quota) 사례와 같이 최소한 하나 이상의 정당한 동기를 가지고 있으므로, 분기에서 음모론을 읽어내지는 마십시오. 그것을 있는 그대로 읽으십시오. 즉, 당신의 도구 신뢰성이 당신이 어떻게 지불하느냐에 따라 조용히 좌우되지만, 아무도 당신에게 말해주지 않은 지점 말입니다.
직접 확인해 보십시오
제 말만 믿지 마시고, 본인의 티어(tier)에서 직접 확인해 보십시오. 모든 API 응답에는 allowed 또는 rejected 상태를 나타내는 anthropic-ratelimit-unified-status 헤더가 포함되어 있으며, 클라이언트는 재시도(retry)가 발생할 때마다 tengu_api_retry 텔레메트리(telemetry)를 방출합니다. 429 에러가 발생할 때까지 워크로드(workload)를 실행한 후 확인해 보십시오. 클라이언트가 백오프(back off)하며 복구되는지, 아니면 해당 턴(turn)이 그대로 종료되는지 말입니다. 종량제 키(metered key)에서는 재시도를 수행합니다. Max 플랜에서는 어떤 일이 일어나는지 지켜보십시오. 이 모든 발견 사항은 본인의 로그에서 재현 가능합니다.
저는 이 결과에 내기를 걸겠습니다. 현재 버전은 v2.1.179입니다. 만약 이후 릴리스에서 구독(subscription) 모델에 대해서도 429 에러를 재시도하게 된다면, 그것은 좋은 일입니다. 그것이 올바른 수정이며, 여러분은 누군가의 분석을 믿는 대신 자신의 텔레메트리(telemetry)에서 해당 수정이 적용되는 것을 직접 확인하게 될 것입니다. 그때까지는, 고정 요금을 지불하는 티어가 가장 먼저 포기하는 티어가 될 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기