Skip to content

문제 해결

흔한 shunt 오류와 해결 방법.

Updated View as Markdown
증상 원인 / 해결
ChatGPT auth not found; run codex login shunt가 ~/.codex/auth.json을 읽을 수 없습니다. codex login을 실행하세요.
매핑된 모델에서 authentication_error 만료/부재한 프로바이더 자격 증명 — codex login을 다시 실행하거나 OPENAI_API_KEY를 export하세요. shunt는 백엔드의 실제 detail 메시지를 노출합니다.
Code Assist가 스트림을 닫을 때 Gemini가 완료 대신 실패함 Gemini 성공 응답에는 명시적인 provider finish와 정상적인 transport closure가 모두 필요합니다. 해당 finish가 없는 EOF 또는 [DONE], 유효하지 않은 UTF-8, malformed JSON 또는 미지원 필드, 초과 크기 데이터, 다중 candidate, terminal 이후의 데이터, truncated response는 명시적으로 실패 처리됩니다. Streaming 및 unary 모드는 동일한 terminal 및 provider-error 의미를 적용하며, embedded provider error를 가짜 성공으로 변환하지 않습니다.
Gemini tool history가 dispatch 전에 거부됨 클라이언트에 노출되는 tool_use ID는 진정한 Code Assist 호출 페어링 및 Gemini 3의 thoughtSignature를 보존합니다. 일치하는 ID를 tool_result로 반환하세요. 잘못된 형식, 중복 또는 고아 메타데이터는 복구 없이 거부됩니다. 다른 provider에서 가져온 tool 호출(예: failover 이후)에는 Gemini 서명이 없으므로, Gemini 3에서는 해당 턴의 첫 번째 호출을 거부하지 않고 Google이 문서화한 placeholder 서명을 붙여 보냅니다. 유효한 결과는 다음 요청의 functionResponse가 됩니다. shunt는 이 메타데이터를 영구 저장하거나 다시 쓰지 않습니다.
Gemini의 transient status가 동일한 upstream으로 재시도되지 않음 Gemini generation은 non-idempotent입니다. 응답 헤더 이전에 발생한 것으로 확인된 일시적 연결 또는 타임아웃 오류만 동일한 선택된 토큰, 프로젝트 및 페이로드로 재시도될 수 있습니다. 반환된 상태 코드 및 모든 본문 시점의 실패는 동일한 업스트림으로 재시도하지 않고 즉시 노출됩니다. 예외적으로 단일 자격 증명으로 구성된 auth = "antigravity_oauth" provider는 반환된 429/502/503/504/529 상태를 provider의 retry 정책에 따라 여전히 재시도합니다. 풀링된 Antigravity 계정은 재시도하지 않습니다.
400 … model is not supported when using Codex with a ChatGPT account -codex 슬러그(또는 계정에 부여되지 않은 것)를 사용했습니다. models.json에서 부여된 슬러그(예: gpt-5.6-sol, gpt-5.5)를 사용하거나 upstream_model을 설정하세요.
게이트웨이 로그 upstream refused the account; skipping it until the window ends (또는 You have reached your specified API usage limits, Your credit balance is too low라고 적힌 400/402) Anthropic 프로토콜 업스트림(이러한 거부를 그대로 전달하는 kimi_oauth 풀은 제외)이 계정 전체를 거부했습니다. API 사용 한도, 바닥난 크레딧 잔액, 또는 402 billing_error입니다. shunt는 체인의 다음 업스트림으로 진행하며, refusal 필드가 어떤 경우인지 알려 줍니다. 다른 업스트림이 요청을 처리하지 못했을 때만 클라이언트에 400/402가 보입니다. passthrough가 아닌 업스트림은 이후 You will regain access on … UTC에 적힌 시각까지, 없으면 1시간 동안 새 요청에서 건너뛰며 건너뛰기는 재시작해야만 지워지며 설정 리로드로는 지워지지 않습니다. 원인을 해소하려면 사용 한도라면 한도를 올리고, 크레딧 잔액이라면 잔액을 충전하고, billing_error라면 Anthropic Console에서 결제 정보를 바로잡으세요. 다만 진행 중인 기간이 일찍 끝나지는 않습니다. 건너뛰기는 기간이 끝날 때까지 유지되고, 체인의 모든 항목이 건너뛰기 대상이면 설정한 순서대로 체인을 시도합니다. 요금제에 포함된 Max API 크레딧은 Claude Code 트래픽을 거부한다고 보고되어 있으므로, 이를 쓰는 공유 업스트림은 그 1시간 동안 다른 클라이언트에서도 건너뛰어질 수 있습니다. Claude OAuth 풀에서는 거부한 계정이 그 기간 동안 쿨다운되고 요청은 다음 계정으로 넘어갑니다. 풀 업스트림 자체는 풀의 마지막 응답이 거부일 때만, 가장 빠른 계정이 다시 처리할 수 있을 때까지 건너뜁니다.
/model이 모델을 나열하지 않음 gpt-* id에는 ANTHROPIC_CUSTOM_MODEL_OPTION을 사용하세요; 디스커버리는 claude/anthropic 프리픽스 id만 노출합니다.
opus가 Opus 4.7을 선택하거나 sonnet이 Sonnet 4.6을 선택함 Claude Code의 내장 별칭 표는 게이트웨이 세션에서 해당 티어로 고정합니다. ANTHROPIC_DEFAULT_OPUS_MODEL=claude-opus-5로 클라이언트 측 티어를 고정하거나 shunt에서 id를 다시 매핑하세요. 모델 별칭을 참고하세요.
Opus/Fable의 컨텍스트 윈도우가 200K로 표시됨 Claude Code는 base URL이 api.anthropic.com일 때만 모델의 기본 1M 윈도우를 신뢰합니다. opus[1m] / fable[1m]을 선택하세요. 모델 별칭을 참고하세요.
/model에서 Fable이 없거나 claude-fable-5가 Opus로 폴백함 단순 ANTHROPIC_BASE_URL 뒤에서는 Fable이 필터링됩니다. ANTHROPIC_DEFAULT_FABLE_MODEL=claude-fable-5를 설정하거나 게이트웨이 로그인을 사용하세요. 모델 별칭을 참고하세요.
디스커버리가 절대 발동하지 않음 게이트웨이 자격 증명(ANTHROPIC_AUTH_TOKEN, API 키, 또는 apiKeyHelper)과 CLAUDE_CODE_ENABLE_GATEWAY_MODEL_DISCOVERY=1로 게이팅됩니다. claude --debug → [gatewayDiscovery] 줄로 디버그하세요.
config check failed shunt check를 실행하여 정확한 이유(bind 주소, 라우트의 알 수 없는 프로바이더, 잘못된 어댑터/인증)를 확인하세요.
Claude Code가 로그인을 요청함 shunt가 매핑되지 않은 모델에 대해 전달할 수 있는 Anthropic 자격 증명(ANTHROPIC_AUTH_TOKEN / 로그인)을 설정하세요. base URL만으로는 자격 증명이 아닙니다.
매핑된 모델에서 effort가 medium에 고정됨 CLAUDE_CODE_ALWAYS_ENABLE_EFFORT=1을 설정하세요 — 노력 & 컨텍스트를 참고하세요.
매핑된 모델에서 400 Invalid schema for function '…': '…' is not a 'regex' OpenAI 백엔드는 도구 스키마의 모든 pattern을 Python re로 컴파일하므로 JavaScript 전용 정규식(\p{Cc}, (?<name>…), \u{…})을 거부합니다. Claude Code의 Artifact 도구가 그런 패턴을 포함합니다. shunt는 전달하는 스키마에서 이런 패턴을 제거합니다. strict 모드 밖에서 pattern은 권고 사항이라 힌트만 사라지지만, description이 그 제약을 항상 다시 적어 주지는 않습니다. 여전히 보인다면 업데이트하세요.
매핑된 모델에서 도구 호출이 모든 선택적 매개변수가 채워진 채로 도착함 백엔드는 명시적 strict가 없는 function 도구를 strict 모드 쪽으로 정규화하며, 그 모드에서는 닫힌 매개변수 객체(additionalProperties:false)가 모든 속성을 필수처럼 다뤄 호출자가 설정하지 않은 값까지 모델이 채워 넣습니다. shunt는 전달하는 function 도구와 tool_search_output 안에 재생되는 스펙에 strict:false를 고정해 선택적 속성을 선택적으로 유지합니다; xAI/Grok 라우트에서는 검증되지 않아 필드를 보내지 않고, 네이티브 tool_search는 스키마에 선택적 속성이 없어 생략합니다. 여전히 보인다면 업데이트하세요.
매핑된 모델에서 도구 검색이 비활성 상태(매 턴 모든 도구 스키마가 전송됨) ENABLE_TOOL_SEARCH=true를 설정하세요. Claude Code는 퍼스트파티가 아닌 base URL 뒤에서 낙관적 도구 검색을 자동으로 비활성화합니다. shunt는 tool_reference 블록을 전달하며 미뤄 둔 스키마를 필요할 때 드러냅니다 — ChatGPT / Codex → 도구 검색을 참고하세요.
400 Deferred custom tools are only supported on Anthropic models… Received stealth/ox-alpha(또는 다른 비 Claude 슬러그) Claude Code가 Anthropic이 아닌 Messages 모델에 defer_loading / tool_search_tool_*를 보냈습니다. shunt는 claude* / anthropic/*가 아닌 업스트림 id에서 해당 필드를 제거한 뒤 전달합니다. OpenRouter의 Anthropic 슬러그는 프로토콜을 유지합니다.
도구 검색은 동작하지만 컨텍스트를 회수하지 못함(여전히 텍스트 shim의 캐시 무효화 비용을 지불 중) 네이티브 tool_search는 기본값(“auto”)에서 이미 지원이 검증된 호스트 — ChatGPT/Codex 백엔드와 api.openai.com — 에서만 적용되며, 계열/모델 게이트(스톡 OpenAI/ChatGPT-Codex 계열, gpt-5.4 이상 모델)도 함께 통과해야 합니다. 커스텀 OpenAI 호환 엔드포인트(LiteLLM, vLLM, OpenRouter, 자체 호스팅)는 자동으로 켜지지 않으므로, 프로토콜 지원을 확인한 뒤 tool_search = true를 설정하세요. 알려진 호스트에서 네이티브를 기대했는데 여전히 shim을 쓰고 있다면 tool_search = false를 설정하지 않았는지 확인하세요 — ChatGPT / Codex → 도구 검색 → 네이티브 프로토콜을 참고하세요.
매핑된 모델에서 컨텍스트 길이 오류 후 세션이 멈춤 shunt는 업스트림 오버플로 오류를 prompt is too long …으로 다시 써서 Claude Code가 자동 압축하고 재시도하도록 합니다 — 컨텍스트 오버플로 복구를 참고하세요. 몇 턴마다 반복되면 CLAUDE_CODE_MAX_CONTEXT_TOKENS를 모델의 실제 윈도우로 낮추세요.
Cloudflare 뒤에서 스트림이 죽음(524) sse_keepalive_seconds를 0 대신 기본값(30)으로 유지하세요.
공유 게이트웨이에서 매핑된 모델에 401 누락/유효하지 않은 클라이언트 토큰 — ANTHROPIC_AUTH_TOKEN=<token>(Authorization: Bearer로 수락, 풀 전용 게이트웨이) 또는 ANTHROPIC_CUSTOM_HEADERS="x-shunt-token: <token>"(패스스루 모델이 섞여 있을 때 권장 — 각 호출자의 실제 자격 증명이 슬롯을 하나 확보하도록. Authorization / x-api-key에 실려 온 클라이언트 토큰은 전달되지 않고 그 슬롯에서 제거됩니다)을 설정하세요; 게이트웨이 공유를 참고하세요.
Anthropic 어댑터 모델에서 429 게이트웨이 로그의 rate_limit_kind를 확인하세요. quota(retry-after / anthropic-ratelimit-* 헤더 동반)는 실제 rate limit입니다 — 백오프하거나 병렬 부하를 줄이세요. client-shape-rejection(OAuth 요청, 두 헤더 모두 없고 바디가 "Error"뿐)은 api.anthropic.com이 Claude Code처럼 보이지 않는 구독 OAuth 요청을 거부한 것입니다 — Claude Code가 아닌 클라이언트는 OAuth 토큰 대신 API 키를 사용해야 합니다. 일부 Claude Code 요청은 업스트림이 확인하는 identity 블록 없이 도착합니다 — auto-mode 권한 분류기와, CLAUDE_CODE_ATTRIBUTION_HEADER=0일 때 mod의 $.model.complete 같은 사이드 쿼리입니다. shunt는 auto-mode 분류기와, 허용된 마커가 없는 모든 Claude Code 요청(x-claude-code-session-id, claude-cli/ user agent 또는 x-app: cli로 식별)에 identity를 복원합니다. 이 복원은 나가는 bearer가 구독 OAuth 토큰일 때만 적용되고, 업스트림이 확인하지 않는 count_tokens에는 적용되지 않으며, 빈 x-claude-code-session-id는 Claude Code로 보지 않습니다. 이 복원으로 auto mode가 “model temporarily unavailable”로 fail-closed 되거나 사이드 쿼리가 이 헤더 없는 429로 거부되는 일을 막습니다. quota 429는 그대로 클라이언트에 전달됩니다. 다른 클라이언트와 나머지 요청은 Anthropic 프로바이더 페이지에 설명된 thinking signature 제거를 제외하면 모두 byte-for-byte 패스스루를 유지합니다. 이 확인들을 비싼 모델에서 떼어놓으려면 classifier_model로 고정하세요. no-ratelimit-headers(비-OAuth 자격 증명)는 rate-limit 메타데이터 없는 프로바이더 429입니다 — quota처럼 취급하세요.
Claude Code가 이 세션은 auto mode의 무과금 분류기 요청 대상이 아니라고 알림 auto mode는 각 도구 사용의 분류를 API에 맡기며, 이에 답하는 곳은 api.anthropic.com뿐입니다. Anthropic 라우트에서는 shunt가 그 요청과 응답을 그대로 중계합니다. 다른 업스트림이 처리하는 라우트(Codex/Responses, Cursor, Gemini, Antigravity)에는 중계할 서버 판정이 없으므로, shunt는 아무것도 돌려주지 않는 대신 동작마다 “평가 불가”로 답합니다. 그러면 Claude Code는 해당 동작 하나만 로컬에서 분류하고 다음 턴에 다시 서버에 요청하며, 세션 남은 기간 내내 서버 분류기를 포기하고 자체 과금 분류기로 돌아서지 않습니다. Anthropic 프로토콜 서드파티(Kimi, OpenRouter, DeepSeek 등)로는 요청을 보내기 전에 safeguards 필드와 dangerous-tool-use-* beta 토큰까지 제거합니다. 이 필드를 받아들이는 것으로 확인된 곳이 없고, 필드를 지목하는 400이 오면 Claude Code가 /clear 전까지 auto mode의 모든 도구 사용을 거부하는 반면, 필드를 제거하면 그 턴의 서버 판정만 잃기 때문입니다. 기능을 완전히 끄고 분류를 클라이언트에 두려면 CLAUDE_CODE_AUTO_MODE_SERVER=0을 설정하세요.
공유 게이트웨이에서 503 overloaded_error 게이트웨이가 인바운드 동시성 상한에 도달해 요청을 대기열에 넣지 않고 거부한 것입니다(바디 메시지 too many requests are already in flight, Retry-After: 1 동반). 업스트림 503이 아니라 shunt 자체의 admission control입니다 — 업스트림 503은 프로바이더의 메시지 그대로 릴레이됩니다. 지정된 시간 뒤에 재시도하거나, 병렬 부하를 줄이거나, max_concurrent_requests를 올리고 재시작하세요(제한은 시작 시점에 고정됩니다).
shunt run이 store … 오류와 함께 시작 시점에 종료됨 선택적 [store]를 열지 못했습니다. 연결·열기 오류에는 저장소 대상이 나오며(비밀번호는 절대 나오지 않음), 아래 스냅샷 가져오기 오류에는 대신 하위 시스템, 스냅샷 경로, 원인이 나옵니다. is held by another shunt instance (<host>:<pid>): 다른 shunt 프로세스가 저장소를 사용 중입니다. 그 프로세스를 중지하거나, 크래시 뒤라면 hold가 stale이 될 때까지(hold_stale_seconds, 기본 30초) 최대 그만큼 기다리세요. 시작 시 store statement failed: … lock timeout(PostgreSQL): 다른 세션이 인스턴스 hold 행을 5초 동안 잠그고 있었습니다. 대개 클라이언트가 사라진 백엔드입니다. pg_stat_activity에서 찾아 pg_terminate_backend로 종료하거나 서버가 정리할 때까지 기다린 뒤 다시 시작하세요. is at schema version N, newer than the M this binary supports: 데이터베이스가 더 새로운 shunt로 마이그레이션되어 있으며 변경되지 않았습니다. shunt를 업그레이드하세요. importing the <subsystem> state snapshot <path> into the store failed: 그 하위 시스템은 아무것도 가져오지 않았습니다. 다만 원인이 커밋 실패라면 가져오기가 이미 반영되었을 수 있으며, 그 경우 다음 부팅에서 이미 가져온 것으로 처리됩니다. 콜론 뒤의 원인을 확인하세요. JSON 스냅샷의 형식이 잘못되었거나 지원하지 않는 버전이면 오류에 나온 파일을 고치거나 제거하고, 파일을 읽을 수 없으면 권한이나 경로를 고치고, 저장소 트랜잭션 실패면 저장소 자체를 점검하세요. 그런 다음 재시작하세요. is unreachable: 데이터베이스에 연결하거나 만들 수 없습니다. shunt check는 시작하지 않고도 같은 원인을 출력합니다. requires a build with the store-postgres feature: 릴리스 바이너리를 쓰거나 --features store-postgres로 빌드하세요.
게이트웨이 /oauth/token이 503 temporarily_unavailable을 반환 [store]가 있을 때 token을 기록하지 못해 발급하지 않았고 변경을 롤백했습니다. refresh token rotation이라면 저장소에 다시 쓸 수 있게 된 뒤 클라이언트의 재시도가 성공합니다. device flow 로그인이라면 승인된 grant가 이미 사용되어 재시도한 poll이 expired_token을 받으므로 로그인을 다시 시작해야 합니다. 어느 경우든 shunt.store.write_failures{subsystem="gateway"} 카운터와 저장소의 디스크·연결을 확인하세요. 경고 로그의 사유가 postgres … did not complete within 15s이면 PostgreSQL 왕복이 15초 안에 응답을 받지 못한 것입니다. 연결이 응답을 멈췄거나 서버가 너무 느린 경우입니다. shunt는 데이터베이스 왕복마다 15초가 지나면 포기하므로, 멈춘 쓰기 뒤에 대기 중인 token 요청은 무한정이 아니라 정해진 시간만 기다립니다. 포기한 단계가 COMMIT이면 shunt가 저장소를 다시 읽어 확인하고, 쓰기가 반영되었으면 요청은 성공하며 경고만 남습니다.

전체 게이트웨이 문제 해결 표는 Connect Claude Code to an LLM gateway를 참고하세요.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close