Skip to content

fix(cli): stop run from sleeping through an exhausted quota - #42289

Closed
DaisukeYoda wants to merge 1 commit into
anomalyco:devfrom
DaisukeYoda:fix/run-exit-on-quota-limit
Closed

DaisukeYoda wants to merge 1 commit into
anomalyco:devfrom
DaisukeYoda:fix/run-exit-on-quota-limit

Conversation

@DaisukeYoda

@DaisukeYoda DaisukeYoda commented Aug 13, 2026 •

Copy link
Copy Markdown

Fixes #40747 — opencode run produces no output and never returns when a model's quota is exhausted.

It isn't wedged, it's sleeping. The quota error is classified as retryable, and delay() honors the provider's retry-after, which for a monthly limit is days. While the schedule sleeps, halt() never runs, so no session.error and no idle are published, and loop() in cli/cmd/run.ts breaks only on idle and has no branch for retry status. The TUI is unaffected because it shows the retry in its footer; a headless run has nowhere to show it.

I left the retry timing alone — honoring long retry-after values was deliberate in 0a2d7af, and waiting out a short rate limit is useful. The change is only in the non-interactive loop:

  • print the retry status, which today prints nothing at all in headless runs
  • exit non-zero when action.reason is free_tier_limit / account_rate_limit; transient retries (429/5xx) carry no action.reason and still wait and retry as before
  • abort the session before returning, because breaking out of the loop isn't enough to end the process — the sleeping schedule holds the in-process server open, and without the abort it still has to be killed

How I verified it

New test in test/cli/run/run-process.test.ts: the test provider returns a 429 carrying GoUsageLimitError with retry-after: 345600, and the run must exit non-zero and mention the limit on stderr. On unmodified dev it hangs until the harness kills it at 30 s; with this change it passes in ~2 s.

Setting that header needed an optional headers argument on httpError() / llm.error() in the test harness — retry-after drives the delay and there was no way to set it before.

bun test test/session/retry.test.ts test/cli/run/ → 250 pass, 5 skip, 0 fail. tsc --noEmit matches the dev baseline.

@github-actions github-actions Bot added the needs:compliance This means the issue will auto-close after 2 hours. label Aug 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

This PR doesn't fully meet our contributing guidelines and PR template.

What needs to be fixed:

  • PR description is missing required template sections. Please use the PR template.

Please edit this PR description to address the above within 2 hours, or it will be automatically closed.

If you believe this was flagged incorrectly, please let a maintainer know.

Quota errors are retryable, and the retry schedule honors the provider's
retry-after, which for a monthly limit is days. While it sleeps, halt()
never runs, so no session.error and no idle are published. The
non-interactive loop breaks only on idle and ignores retry status, so it
waits with no output and no exit.

Handle retry status in that loop: print it, and exit non-zero when
action.reason marks the limit as non-transient. Transient retries carry
no action.reason and still wait and retry as before. The session is
aborted first because the sleeping schedule otherwise keeps the process
alive after the loop breaks.

Retry timing is unchanged; honoring long retry-after values is
deliberate (0a2d7af).

Fixes anomalyco#40747
@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically closed because it was not updated to meet our contributing guidelines within the 2-hour window.

Feel free to open a new pull request that follows our guidelines.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

opencode run hangs indefinitely when the usage quota is exhausted, instead of reporting the error it already has

1 participant