환경
- opencodex 2.7.41 (launchd 상주, port 10100)
- Claude Desktop 3P 모드 (gateway key 방식) + Claude Code 2.1.218~219
- anthropic provider = Claude OAuth (Pro/Max), Auto Mode classifier 모델 =
claude-sonnet-5
- macOS, Auto Mode(권한 자동판정) 켠 상태
증상
Auto Mode 세션에서 도구 호출마다 Claude Code가 Sonnet 권한 분류 요청을 보내는데, 이 요청이 정확히 output 64토큰에서 max_tokens로 잘리고, 같은 입력으로 최대 5회 연속 반복됩니다. 대시보드에는 502(upstream_server_error)로 쌓이고, 도구 하나 승인에 12~22초씩 걸립니다. 여러 세션/병렬 도구 사용 시 체감 속도가 크게 저하됩니다.
~/.opencodex/usage.jsonl 집계 (한 세션 며칠 누적):
status:502, terminalStatus:incomplete, upstreamError:"Upstream incomplete: max_output_tokens", outputTokens:64 → 1,084건
- 64 미만에서 정상 종료(200) → 143건
- 동일 입력토큰 연속 클러스터 232개 (길이 5가 112개 — 재시도 상한 도달로 추정)
10:55:28 502 out=64 → 10:55:31 502 → 10:55:34 502 → 10:55:36 502 → 10:55:39 502
10:54:36 502 out=64 → 10:54:38 502 → 10:54:42 200 out=63 ← 태그가 64토큰 안에 닫힌 경우
원인 분석 (Claude Code 바이너리 + opencodex 소스 대조)
Claude Code의 Auto 분류기는 max_tokens 64, stop_sequences: ["</block>"](또는 </severity>), skipSystemPromptPrefix로 짧은 XML 판정을 받는 설계입니다. 64토큰 안에 태그가 안 닫히면 파싱 실패로 같은 요청을 재시도합니다.
Desktop 3P는 gateway key(ocx)라 wantsNativePassthrough()(src/server/claude-messages.ts:91)가 false → Messages→Responses→Messages 이중 번역 경로를 타는데, 이 과정에서 원 요청과 달라지는 점:
- identity 블록 강제 삽입 — anthropic OAuth 경로에서
CLAUDE_CODE_SYSTEM_INSTRUCTION을 system 첫 블록에 prepend (src/adapters/anthropic.ts). 원 요청은 skipSystemPromptPrefix를 명시한 분류기 요청이라 1P 대비 프롬프트가 달라짐
- thinking/effort 관련 필드가 왕복 변환에서 소실 (실패 1,084건 전부
requestedEffort 부재)
- 이중 번역 자체로 인한 프롬프트 형태의 미세 변화
프롬프트가 1P와 달라지니 응답 길이 분포가 밀려 64토큰 상한에 걸리는 빈도가 급증하는 것으로 추정합니다. (1P 쪽 분류 요청은 관측 불가라 실패율 직접 비교는 못 했습니다 — 가설 부분은 검증 환영)
제안
- A (핵심): anthropic provider로 라우팅되는
claude-* 모델은 gateway key여도 Anthropic body를 왕복 번역 없이 그대로 전달(auth/system 첫 블록 요건만 처리)하는 direct bridge 검토
- B (완화): inbound system에 이미 Claude Code identity가 있으면 중복 prepend 생략, thinking/effort 필드 보존
- C (별건): request log가
incomplete/max_output_tokens를 502 upstream_server_error로 표기 (src/server/request-log.ts httpStatusForTerminalStatus) — 실제 HTTP는 200이고 서버 오류가 아니어서 진단에 혼선. 별도 상태/라벨 제안
재현: Desktop 3P + anthropic OAuth 라우팅 + Auto Mode 세션에서 도구 몇 개 실행 → usage.jsonl에서 sonnet/out=64/502 클러스터 확인. 로그 필요하면 제공 가능합니다.
Translated Message
Original language: Korean
Environment
- opencodex 2.7.41 (running on launchd, port 10100)
- Claude Desktop 3P mode (using gateway key) + Claude Code 2.1.218~219
- anthropic provider = Claude OAuth (Pro/Max), Auto Mode classifier model =
claude-sonnet-5
- macOS, Auto Mode (automatic permission determination) enabled
Symptoms
In the Auto Mode session, Claude Code sends a Sonnet permission classification request for each tool call, and this request is cut off exactly at 64 tokens by max_tokens, and is repeated up to 5 times consecutively with the same input. It accumulates 502 (upstream_server_error) on the dashboard, and it takes 12 to 22 seconds to approve a single tool. The perceived speed significantly decreases when using multiple sessions/parallel tools.
~/.opencodex/usage.jsonl aggregation (compiled over several days for one session):
status:502, terminalStatus:incomplete, upstreamError:"Upstream incomplete: max_output_tokens", outputTokens:64 → 1,084 occurrences
- Normal termination (200) below 64 → 143 occurrences
- Continuous clusters of the same input tokens 232 (length 5 is 112 — estimated due to reaching retry limit)
10:55:28 502 out=64 → 10:55:31 502 → 10:55:34 502 → 10:55:36 502 → 10:55:39 502
10:54:36 502 out=64 → 10:54:38 502 → 10:54:42 200 out=63 ← case where tags close within 64 tokens
Cause Analysis (Comparing Claude Code binary + opencodex source)
The Auto classifier of Claude Code is designed to receive a short XML determination with max_tokens of 64, stop_sequences: ["</block>"] (or </severity>), and skipSystemPromptPrefix. If tags do not close within 64 tokens, it retries the same request due to parsing failure.
Desktop 3P is gateway key (ocx) so wantsNativePassthrough() (src/server/claude-messages.ts:91) returns false → Messages→Responses→Messages double translation path is taken, resulting in differences from the original request:
- Forced insertion of identity block — prepends
CLAUDE_CODE_SYSTEM_INSTRUCTION to the first block of the system in the anthropic OAuth path (src/adapters/anthropic.ts). The original request is a classifier request explicitly stating skipSystemPromptPrefix, resulting in a different prompt compared to 1P.
- Fields related to thinking/effort are lost during round-trip conversion (all 1,084 failed requests lack
requestedEffort)
- Subtle changes in prompt form due to double translation itself
Due to the difference in prompt from 1P, it is presumed that the frequency of hitting the upper bound of 64 tokens increases drastically. (It is not possible to directly compare failure rates as the classifier requests on the 1P side are not observable — verification of this hypothesis is welcome)
Suggestions
- A (Core): Consider implementing a direct bridge that transmits
claude-* models routed via the anthropic provider without round-trip translation, preserving only the first block requirements of the auth/system.
- B (Mitigation): If there is already a Claude Code identity in the inbound system, omit duplicate prepend and preserve thinking/effort fields.
- C (Other): The request log notes
incomplete/max_output_tokens as 502 upstream_server_error (src/server/request-log.ts httpStatusForTerminalStatus) — the actual HTTP is 200 and not a server error, leading to confusion in diagnosis. A separate status/label suggestion.
Reproduction: Run a few tools in the session with Desktop 3P + anthropic OAuth routing + Auto Mode → check for sonnet/out=64/502 clusters in usage.jsonl. Logs can be provided if needed.
환경
claude-sonnet-5증상
Auto Mode 세션에서 도구 호출마다 Claude Code가 Sonnet 권한 분류 요청을 보내는데, 이 요청이 정확히 output 64토큰에서
max_tokens로 잘리고, 같은 입력으로 최대 5회 연속 반복됩니다. 대시보드에는 502(upstream_server_error)로 쌓이고, 도구 하나 승인에 12~22초씩 걸립니다. 여러 세션/병렬 도구 사용 시 체감 속도가 크게 저하됩니다.~/.opencodex/usage.jsonl집계 (한 세션 며칠 누적):status:502, terminalStatus:incomplete, upstreamError:"Upstream incomplete: max_output_tokens", outputTokens:64→ 1,084건원인 분석 (Claude Code 바이너리 + opencodex 소스 대조)
Claude Code의 Auto 분류기는
max_tokens64,stop_sequences: ["</block>"](또는</severity>),skipSystemPromptPrefix로 짧은 XML 판정을 받는 설계입니다. 64토큰 안에 태그가 안 닫히면 파싱 실패로 같은 요청을 재시도합니다.Desktop 3P는 gateway key(
ocx)라wantsNativePassthrough()(src/server/claude-messages.ts:91)가 false → Messages→Responses→Messages 이중 번역 경로를 타는데, 이 과정에서 원 요청과 달라지는 점:CLAUDE_CODE_SYSTEM_INSTRUCTION을 system 첫 블록에 prepend (src/adapters/anthropic.ts). 원 요청은skipSystemPromptPrefix를 명시한 분류기 요청이라 1P 대비 프롬프트가 달라짐requestedEffort부재)프롬프트가 1P와 달라지니 응답 길이 분포가 밀려 64토큰 상한에 걸리는 빈도가 급증하는 것으로 추정합니다. (1P 쪽 분류 요청은 관측 불가라 실패율 직접 비교는 못 했습니다 — 가설 부분은 검증 환영)
제안
claude-*모델은 gateway key여도 Anthropic body를 왕복 번역 없이 그대로 전달(auth/system 첫 블록 요건만 처리)하는 direct bridge 검토incomplete/max_output_tokens를 502upstream_server_error로 표기 (src/server/request-log.tshttpStatusForTerminalStatus) — 실제 HTTP는 200이고 서버 오류가 아니어서 진단에 혼선. 별도 상태/라벨 제안재현: Desktop 3P + anthropic OAuth 라우팅 + Auto Mode 세션에서 도구 몇 개 실행 → usage.jsonl에서 sonnet/out=64/502 클러스터 확인. 로그 필요하면 제공 가능합니다.
Translated Message
Original language: Korean
Environment
claude-sonnet-5Symptoms
In the Auto Mode session, Claude Code sends a Sonnet permission classification request for each tool call, and this request is cut off exactly at 64 tokens by
max_tokens, and is repeated up to 5 times consecutively with the same input. It accumulates 502 (upstream_server_error) on the dashboard, and it takes 12 to 22 seconds to approve a single tool. The perceived speed significantly decreases when using multiple sessions/parallel tools.~/.opencodex/usage.jsonlaggregation (compiled over several days for one session):status:502, terminalStatus:incomplete, upstreamError:"Upstream incomplete: max_output_tokens", outputTokens:64→ 1,084 occurrencesCause Analysis (Comparing Claude Code binary + opencodex source)
The Auto classifier of Claude Code is designed to receive a short XML determination with
max_tokensof 64,stop_sequences: ["</block>"](or</severity>), andskipSystemPromptPrefix. If tags do not close within 64 tokens, it retries the same request due to parsing failure.Desktop 3P is gateway key (
ocx) sowantsNativePassthrough()(src/server/claude-messages.ts:91) returns false → Messages→Responses→Messages double translation path is taken, resulting in differences from the original request:CLAUDE_CODE_SYSTEM_INSTRUCTIONto the first block of the system in the anthropic OAuth path (src/adapters/anthropic.ts). The original request is a classifier request explicitly statingskipSystemPromptPrefix, resulting in a different prompt compared to 1P.requestedEffort)Due to the difference in prompt from 1P, it is presumed that the frequency of hitting the upper bound of 64 tokens increases drastically. (It is not possible to directly compare failure rates as the classifier requests on the 1P side are not observable — verification of this hypothesis is welcome)
Suggestions
claude-*models routed via the anthropic provider without round-trip translation, preserving only the first block requirements of the auth/system.incomplete/max_output_tokensas 502upstream_server_error(src/server/request-log.tshttpStatusForTerminalStatus) — the actual HTTP is 200 and not a server error, leading to confusion in diagnosis. A separate status/label suggestion.Reproduction: Run a few tools in the session with Desktop 3P + anthropic OAuth routing + Auto Mode → check for sonnet/out=64/502 clusters in usage.jsonl. Logs can be provided if needed.