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
[Bug] opencode-go returns AI_APICallError: Insufficient Balance on deepseek-v4-pro and deepseek-v4-flash despite active Go subscription with 50% usage remaining #27598
Same error occurs for deepseek-v4-flash (which also consumes Go subscription quota — it is not free via opencode-go).
Key observation
Provider
Model
Consumes quota
Result
opencode-go
deepseek-v4-pro
Go subscription
❌ Insufficient Balance
opencode-go
deepseek-v4-flash
Go subscription
❌ Insufficient Balance
opencode (Zen, non-Go)
deepseek-v4-flash-free
Free
✅ Works
Note: deepseek-v4-flash-free is only free when accessed via providerID=opencode (Zen). Via opencode-go, deepseek-v4-flash consumes Go subscription quota. Both paid Go models fail while the Zen free model works — this confirms the issue is with the opencode-go backend's upstream DeepSeek account balance, not the user's personal quota or API key.
Multiple API keys have been tried. /connect was redone from scratch. The problem persists across all keys.
Steps to reproduce
Active OpenCode Go subscription with usage remaining
Breaks: --format json mode (used by any programmatic consumer, e.g. opendesign)
Root cause: trailing SSE event after [DONE]
The opencode-go backend sends a non-standard SSE event after the stream terminates:
data: {"id":"...","choices":[{"index":0,"delta":{"content":"ok"},"finish_reason":"stop"}]}
data: [DONE]
data: {"choices":[],"cost":"0"} ← this event should not exist after DONE
opencode's --format json subprocess mode parses the stream sequentially. When it processes {"choices":[],...} after [DONE], it sees an empty choices array and overwrites the assembled message with empty content. The session loop never emits exiting loop and never sends HTTP 200 back to the caller.
Evidence from opencode's own log (~/.local/share/opencode/log/):
# Content IS streaming (bus events fire normally):
INFO service=bus type=message.part.delta publishing ← repeated many times
INFO service=bus type=message.part.updated publishing
INFO service=bus type=message.updated publishing
INFO service=bus type=session.status publishing
# ← process exits here. No "exiting loop", no "http.status=200"
Compare to a working session (Claude provider), which shows:
INFO service=session.prompt step=1 exiting loop
INFO service=bus type=session.idle publishing
INFO http.method=POST http.url=/session/.../message http.status=200 Sent HTTP response
A programmatic consumer (opendesign) catches this as:
[test:agent] OpenCode → no_text (exit 0)
— opencode exited 0 but getText() was empty (the content was assembled internally but never flushed to the stdout JSON stream).
TUI vs --format json
The TUI mode either ignores post-DONE events or doesn't re-parse them. --format json mode re-processes every SSE event sequentially, so it gets tripped by the trailing one. This is why opencode run in a terminal works perfectly while any programmatic consumer fails.
Suggested fix
On the backend: stop emitting data: {"choices":[],"cost":"0"} after data: [DONE]. If cost reporting is needed, include it in the final non-empty choices event or in a custom header.
On the client side: ignore any SSE event that arrives after data: [DONE] has been seen.
Activity
github-actions commentedon May 14, 2026
This issue might be a duplicate of existing issues. Please check:
402 Insufficient Balanceonopencode-go, reported the same daydeepseek-v4-flashviaopencode-go(now closed)opencode-goPlease review these issues to see if your problem is already tracked. If it is, consider adding a comment there instead to consolidate information.
joaomj commentedon May 14, 2026
i am facing the same problem.
CamiloFernando commentedon May 14, 2026
Reproducing "Agent completed without producing any output" in
--format jsonmodeAdding a reproduction for the empty-response failure that differs from the balance/credits angle in the OP.
Environment
1.14.50opencode-gomimo-v2.5,deepseek-v4-pro,glm-5.1(all reasoning models)opencode run)--format jsonmode (used by any programmatic consumer, e.g. opendesign)Root cause: trailing SSE event after
[DONE]The
opencode-gobackend sends a non-standard SSE event after the stream terminates:Reproduce with:
What breaks
opencode's
--format jsonsubprocess mode parses the stream sequentially. When it processes{"choices":[],...}after[DONE], it sees an empty choices array and overwrites the assembled message with empty content. The session loop never emitsexiting loopand never sendsHTTP 200back to the caller.Evidence from opencode's own log (
~/.local/share/opencode/log/):Compare to a working session (Claude provider), which shows:
A programmatic consumer (opendesign) catches this as:
— opencode exited 0 but
getText()was empty (the content was assembled internally but never flushed to the stdout JSON stream).TUI vs
--format jsonThe TUI mode either ignores post-DONE events or doesn't re-parse them.
--format jsonmode re-processes every SSE event sequentially, so it gets tripped by the trailing one. This is whyopencode runin a terminal works perfectly while any programmatic consumer fails.Suggested fix
On the backend: stop emitting
data: {"choices":[],"cost":"0"}afterdata: [DONE]. If cost reporting is needed, include it in the final non-empty choices event or in a custom header.On the client side: ignore any SSE event that arrives after
data: [DONE]has been seen.r3vs commentedon May 15, 2026
Im closing this it's working since yesterday night.