Skip to content

[Bug]: adapter and runTurn report send-budget exhaustion as 502 upstream_error #4708

Description

@lidge-jun

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

  1. Configure a routed provider whose adapter runs inner retries (Kiro or Cursor, or any provider with a transient retry policy).
  2. Drive a request until the shared request send budget is spent, then force one more recovery leg.
  3. Observe 502 upstream_error from the adapter path where the passthrough path would have returned 429 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinglanded-via-maintainerOriginal PR closed after landing via a maintainer merge trainstreamingSSE, WebSocket, terminal stream frames

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions