You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
opencode run hangs indefinitely when the usage quota is exhausted, instead of reporting the error it already has #40747
When a model's usage quota is exhausted, opencode runnever exits and never
reports the reason. The process hangs indefinitely with no output on stdout and
nothing but a banner on stderr — even though the error is known internally within
~170 ms and written to opencode's own log file.
Any non-interactive use (scripts, CI, an app shelling out to the CLI) therefore
hangs until an external timeout kills it, and the caller has no way to tell an
exhausted quota from a slow model.
The interactive TUI handles this case properly, so this looks specific to the
non-interactive run path.
Version
opencode 1.17.11, Linux x86_64.
Reproduction
With a subscription whose quota is exhausted:
$ timeout 90 opencode run --model opencode-go/<any-model>"say hi"rc=124 # killed by `timeout`, not by opencodestdout: 0 bytesstderr: 34 bytes # only: ESC[0m "> build · <model>" ESC[0m
Same result with --format json (stdout and stderr both 0 bytes), and at
120 s and 300 s ceilings. The process never terminates on its own.
It knows almost immediately
--print-logs --log-level DEBUG on the same run:
11:42:33.920 INFO run=… message=stream providerID=opencode-go modelID=<model> …
11:42:34.091 ERROR run=… message="stream error" … error.error="AI_APICallError: Monthly usage limit reached. Resets in N days. …"
11:42:36.448 ERROR run=… message="stream error" … small=true agent=title … error.error="AI_RetryError: Failed after 3 attempts. Last error: Monthly usage limit reached. …"
171 ms from stream start to a fully-formed error. It reaches the log file and
then goes nowhere else, and the process continues to hang.
(The second line is the title-generation agent hitting the same wall after its
own retries — possibly relevant to why the run never unwinds.)
Expected
opencode run should exit non-zero and print the provider's error. With --format json, emitting the existing error envelope on stdout would be enough:
That is the shape errors already take on that stream, so a caller could parse it
with no new contract.
Actual
Exit code: none — the process must be killed externally.
stdout: empty.
stderr: a decorative banner only.
Why it matters
A CLI that hangs forever is worse than one that fails: a wrapper cannot
distinguish "out of quota" from "model is slow" and has to wait out its full
timeout budget before giving up, on every subsequent call too. Exiting non-zero
with the message that is already in hand would make this a two-line failure
instead.
Identifiers (workspace, session, run ids) redacted from the log excerpts above.
Same thing on macOS 15.3.1 arm64 with opencode 1.18.15, so it isn't Linux- or 1.17.11-specific.
Mine ran 78 hours before I killed it by hand — there's no eventual unwind, the 90/300 s ceilings above were just far too short. It wasn't blocked on a dead socket either: 55 min of CPU over 78.9 h, and the only thing it logged that whole time was its hourly snapshot cleanup.
Three of them had piled up. They were wrapped in caffeinate -i, so the machine couldn't sleep for 3 days, and launchd won't relaunch a job whose previous instance is still alive — so the scheduled runs silently stopped happening with no failure signal anywhere. That last part is the one that hurt: it's not just "job hangs", it's "job hangs and quietly disables every later run".
(I filed #42268 before spotting this issue; closed as a duplicate.)
Traced it: the process is sleeping until the quota resets.
retryable() classifies GoUsageLimitError as retryable, and delay() honors the provider's retry-after — days, for a monthly limit. 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 with no branch for retry status.
My logs match: only level=INFO message=process, never the ERROR one halt() writes. And with no retry-after header the 5 retries would have finished in under 3 minutes and exited 1, which isn't what happened.
Worth noting for whoever picks this up: the long sleep looks intentional (0a2d7af removed an earlier 10-minute cap, with tests). PR #42289 leaves the timing alone and only changes the non-interactive loop.
We’re seeing a similar symptom in Obsidian Copilot, which uses OpenCode through ACP rather than opencode run.
With OpenCode 1.18.16, a user’s logs show Gemini high-demand errors and a free-tier quota error, followed by retries. The UI eventually stops generating without an answer or error banner.
One difference: our ACP trace shows the affected turns returning stopReason: "end_turn" with outputTokens: 0, rather than remaining pending indefinitely. So this may be a related error-propagation gap rather than the same retry-sleep bug.
Does the proposed fix also cover ACP? It would help ACP clients to receive session-scoped retry status, including the provider’s reason and next retry time, and a protocol-visible error when the turn cannot continue. Currently, users have to inspect opencode.log to discover that the provider encountered an error.
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.
Activity
DaisukeYoda commentedon Aug 13, 2026
Same thing on macOS 15.3.1 arm64 with opencode 1.18.15, so it isn't Linux- or 1.17.11-specific.
Mine ran 78 hours before I killed it by hand — there's no eventual unwind, the 90/300 s ceilings above were just far too short. It wasn't blocked on a dead socket either: 55 min of CPU over 78.9 h, and the only thing it logged that whole time was its hourly snapshot cleanup.
Three of them had piled up. They were wrapped in
caffeinate -i, so the machine couldn't sleep for 3 days, and launchd won't relaunch a job whose previous instance is still alive — so the scheduled runs silently stopped happening with no failure signal anywhere. That last part is the one that hurt: it's not just "job hangs", it's "job hangs and quietly disables every later run".(I filed #42268 before spotting this issue; closed as a duplicate.)
DaisukeYoda commentedon Aug 13, 2026
Traced it: the process is sleeping until the quota resets.
retryable()classifiesGoUsageLimitErroras retryable, anddelay()honors the provider'sretry-after— days, for a monthly limit. While the schedule sleeps,halt()never runs, so nosession.errorand noidleare published, andloop()incli/cmd/run.tsbreaks only onidlewith no branch forretrystatus.My logs match: only
level=INFO message=process, never the ERROR onehalt()writes. And with noretry-afterheader the 5 retries would have finished in under 3 minutes and exited 1, which isn't what happened.Worth noting for whoever picks this up: the long sleep looks intentional (0a2d7af removed an earlier 10-minute cap, with tests). PR #42289 leaves the timing alone and only changes the non-interactive loop.
fix(cli): stop `run` from sleeping through an exhausted quota
zeroliu commentedon Sep 8, 2026
We’re seeing a similar symptom in Obsidian Copilot, which uses OpenCode through ACP rather than opencode run.
With OpenCode 1.18.16, a user’s logs show Gemini high-demand errors and a free-tier quota error, followed by retries. The UI eventually stops generating without an answer or error banner.
One difference: our ACP trace shows the affected turns returning stopReason: "end_turn" with outputTokens: 0, rather than remaining pending indefinitely. So this may be a related error-propagation gap rather than the same retry-sleep bug.
Does the proposed fix also cover ACP? It would help ACP clients to receive session-scoped retry status, including the provider’s reason and next retry time, and a protocol-visible error when the turn cannot continue. Currently, users have to inspect opencode.log to discover that the provider encountered an error.
Our report and logs: logancyang/obsidian-copilot#3104
thdxr commentedon Oct 11, 2026
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (
opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊