Repository navigation
[Bug]: adapter and runTurn report send-budget exhaustion as 502 upstream_error #4708
Description
Client or integration
Other
Area
Streaming
Summary
When a request exhausts its shared send budget, the three dispatch paths disagree about what the client is told.
The passthrough path returns 429 request_send_budget_exhausted and explicitly declines to blame the provider (src/server/responses/passthrough-dispatch.ts:693-700). The adapter path does not special-case SendBudgetExhaustedError: it falls through describeUpstreamConnectFailure and surfaces 502 upstream_error — "Provider unreachable" — for a refusal this proxy made itself (src/server/responses/adapter-dispatch.ts:331-335, :483-488). The runTurn path pushes a generic error event into the SSE bridge, so the client sees response.failed under HTTP 200 (src/server/responses/run-turn-execution.ts:167-180).
Separately, the terminal-guard continuation loop never consults sendBudgetExhausted() (src/server/responses/adapter-continuation.ts:260-264) while the main recovery loop does (adapter-dispatch.ts:593), so a spent budget can still same-key 429-replay on a live stream.
Both predate 2.56.0; they are recorded here so the disagreement is tracked rather than rediscovered.
Reproduction
- Configure a routed provider whose adapter runs inner retries (Kiro or Cursor, or any provider with a transient retry policy).
- Drive a request until the shared request send budget is spent, then force one more recovery leg.
- Observe
502 upstream_errorfrom the adapter path where the passthrough path would have returned429 request_send_budget_exhausted.
Suggested fix: in both adapter catch sites, check err instanceof SendBudgetExhaustedError before describeUpstreamConnectFailure and return the same 429 the passthrough path returns; map the runTurn case to a 429 before the SSE response is committed; and gate the continuation 429 loop on sendBudgetExhausted().
Version
2.56.0 (e4a8539)
Operating system
macOS 15.5
Provider and model
kiro / any; also reproduces on providers with a transient retry policy
Logs or error output
Provider unreachable: <host> (observed where a 429 request_send_budget_exhausted was expected)Checks
- I searched existing issues and documentation.
- I removed secrets, tokens, account details, request credentials, and personal data.
Activity
lidge-jun commentedon Sep 15, 2026
리뷰 · 우선순위 73 / 80
이 이슈는 공유 send budget이 바닥났을 때 세 dispatch 경로가 클라이언트에게 다른 답을 주는 불일치다. tip
51d577c3f에서 passthrough는429 request_send_budget_exhausted를 돌려 공급자 탓을 하지 않는다(src/server/responses/passthrough-dispatch.ts). 어댑터 경로(adapter-dispatch.ts약 331–335, 483–502행)는SendBudgetExhaustedError를 특별 처리하지 않고describeUpstreamConnectFailure로 떨어뜨려502 upstream_error(Provider unreachable)를 만든다.run-turn-execution.tscatch는 pacing overload만 429로 매핑하고, 그 외 에러는 SSEerror이벤트로 밀어 HTTP 200 위response.failed처럼 보이게 한다.추가로 터미널 가드 continuation(
adapter-continuation.ts약 258–270행)의 same-key 429 루프는sendBudgetExhausted()를 보지 않는다. 본선 recovery 루프(adapter-dispatch 약 513·608행)는 본다. 예산이 이미 소진된 뒤에도 live stream continuation이 same-key 429 replay를 시도할 수 있다. 둘 다 2.56.0 이전부터 있던 부채로, 감사에서 ‘다시 발견하지 말자’고 이슈화한 형태다.운영 영향은 크다. 프록시가 스스로 거절한 요청을 upstream 장애로 보이게 하면 재시도·알람·풀 회전이 잘못 움직인다. 수정은 이슈 제안이 명확하다. 어댑터 catch 두 곳에서
instanceof SendBudgetExhaustedError를 먼저 보고 passthrough와 같은 429를 돌려주고, runTurn도 SSE commit 전에 429로 매핑하며, continuation 429 루프에sendBudgetExhausted()가드를 넣는다.경로
src/server/responses/adapter-dispatch.tscatch - budget 소진을 502 upstream_error로 위장.경로
src/server/responses/run-turn-execution.ts- SendBudgetExhaustedError가 generic SSE error로 떨어짐.경로
src/server/responses/adapter-continuation.tssame-key 429 while -sendBudgetExhausted()미상담.경로
passthrough-dispatch.ts- 이미 올바른 429 계약. 기준으로 삼을 것.메인테이너의 판단이 필요한 지점
너의 추천
받아라. 한 PR로 어댑터 두 catch + runTurn 매핑 + continuation 가드를 맞추고, Kiro/Cursor 예산 소진 픽스처로 429 코드가 세 경로에서 같은지 검증하라.
이 댓글은 grok-bot이 작성했습니다
Merge pull request #4758 from lidge-jun/codex/bl3-budget-refusal-sema…
lidge-jun commentedon Sep 16, 2026
Landed via #4758 at 6e254f3.
fix(responses): report a spent send budget as this proxy refusing (li…
fix(responses): report a spent send budget as this proxy refusing (li…
Merge pull request lidge-jun#4758 from lidge-jun/codex/bl3-budget-ref…