anomalyco / anomalyco/opencode
opencode run hangs indefinitely when the usage quota is exhausted, instead of reporting the error it already has
@rekram1-node is already working on this.
Since Aug 5, 2026.
- Dominant language
- TypeScript
- Stars
- 209k
- Forks
- 27.5k
- PR merge metrics
- PR metrics pending
Description
Summary
When a model's usage quota is exhausted, opencode run never 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 opencode
stdout: 0 bytes
stderr: 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:
{"type":"error","error":{"type":"GoUsageLimitError","message":"Monthly usage limit reached. …"}}
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.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.