Repository navigation
Description
Summary
Requests to opencode-go/deepseek-v4.1-flash intermittently die mid-stream with upstream admission-control errors (prefill_cap_refused / ttft_admission_refused, "the cell is at capacity"), and the turn is not retried even though the error says "retry shortly". Retrying the same message succeeds, so a transient capacity rejection is surfaced as a hard failure.
Environment
- opencode version: 2.2.5
- OS: Windows 10.0.26200.9457 (win32 x64)
- Terminal: VS Code integrated terminal (TERM_PROGRAM=vscode, TERM=xterm-256color, COLORTERM=truecolor)
- Shell: C:\WINDOWS\system32\cmd.exe
- Install/channel: latest (npm global)
- Active plugins: none (neither project
opencode.jsonnor~/.config/opencode/opencode.jsoncdefines plugins)
Reproduction
- Start OpenCode 2.2.5 and select
opencode-go/deepseek-v4.1-flash. - Run a normal multi-turn session with tools and a moderate-to-large context.
- Intermittently a turn aborts with the error below; sending the same message again succeeds.
Not deterministically reproducible: it depends on upstream load and appears in bursts.
Expected Behavior
A transient upstream capacity rejection should either be retried with the delay the upstream returns ("retry shortly (after N s)"), or be surfaced as a retryable/backoff state instead of terminating the stream. Ideally the user sees "provider busy, retrying" rather than a dead turn.
Actual Behavior
The turn ends with:
AI_APICallError: Upstream request failed: [prefill_cap_refused] the cell is at capacity; retry shortly (after 5 s)
and in earlier sessions:
AI_APICallError: Upstream request failed: [ttft_admission_refused] the cell is at capacity; retry shortly (after 14 s)
Additional Context
- 43 matching errors in
~/.local/share/opencode/log/opencode.log: 24 on 2026-10-27, 18 on 2026-10-28, 4 on 2026-11-06. - Every occurrence is
providerID=opencode-go,modelID=deepseek-v4.1-flash; no other provider/model is affected. - 42 x
ttft_admission_refused, 1 xprefill_cap_refused; upstream-suggested retry delays range from 3 s to 59 s. - Log line shape (session id redacted):
timestamp=2026-11-06T07:43:39.867Z level=ERROR run=<id> message="stream error" providerID=opencode-go modelID=deepseek-v4.1-flash session.id=<redacted> small=false agent=build mode=primary error.error="AI_APICallError: Upstream request failed: [prefill_cap_refused] the cell is at capacity; retry shortly (after 5 s)"
- Workarounds: resending the failed message works; switching to another model on the same provider also works.
- V2 provider config documents no retry/backoff option, so this cannot be tuned from
opencode.json.
Activity
opencodejr commentedon Nov 6, 2026
Thanks for the detailed report and the log counts, they helped a lot.
I couldn't reproduce this end to end. It needs a real OpenCode Go account at the moment the model is overloaded, and that part of the system runs on the OpenCode Go service, not in this repository. I did test the client side on 2.2.5 with a mock endpoint that sends the exact error from your logs once, then a normal reply:
The second case is deliberate: OpenCode treats most 4xx responses (other than 429) as a problem with the request itself, so it doesn't retry them. Your turns dying right away with no "retrying" state matches that case. So the Go gateway most likely sends these capacity rejections with a 4xx status. Someone on the team with access to the OpenCode Go service will need to check that.
For now, resending the message or switching models remain the workarounds. Related, but not the same problem: #51530 (OpenCode Go errors hidden behind HTTP 400) and #60753.
chernya2010 commentedon Nov 6, 2026
Thanks — that matches what we see, with one caveat from the client side.
The stream-error log entry does not include the HTTP status or a retryability flag, so a user report can't distinguish the 400 case from the 429 case:
No
statusCode, noisRetryable, no response headers. AddingstatusCode(andRetry-Afterwhen present) to this line would make the next report conclusive and would also help separate gateway bugs from client bugs.Numbers, corrected from my first post: 42 stream-error entries — 23 on 2026-10-27, 18 on 2026-10-28, 1 on 2026-11-06; 41 x
ttft_admission_refused, 1 xprefill_cap_refused; the embedded wait ranges from 2 s to 59 s. All onopencode-go/deepseek-v4.1-flash.Both variants carry an explicit wait ("retry shortly (after N s)"), so the Go gateway could return 429/503 with
Retry-Afterand stay inside the retry path you tested. If the OpenCode Go service is the right tracker, happy to move this there — just point me at the repo.wujun2081 commentedon Nov 7, 2026
Same failure mode on another account, adding data since this appears in bursts rather than as an account-quota issue.
Environment: OpenCode host on OpenMausBot, client version 1.18.31, macOS (Darwin), provider opencode-go, model deepseek-v4.1-flash, active paid Go subscription.
10 upstream capacity refusals across Nov 6-7, 2026 (UTC):
Error text:
Internal error: Upstream request failed: [prefill_cap_refused] the cell is at capacity; retry shortly (after N s).Note this persisted across two separate days and after idle gaps, on a paid Go plan — so it is upstream of any per-account free-tier cap. +1 to auto-retrying transient capacity refusals with the caller-suggested backoff instead of failing the turn.
Yue-bin commentedon Nov 7, 2026
Adding measurements from the server side — direct HTTPS calls to the Go endpoint with no client in the loop — since the bot's analysis points at the OpenCode Go service rather than this repository.
Setup:
POST https://opencode.ai/inference/go/v1/chat/completions, modeldeepseek-v4.1-flash, paid Go account,max_tokens: 4,stream: false, varying onlyx-opencode-session. Sizes are approximate (English filler, ~4 chars/token); times are wall clock, request → full response.What this says
/inference/go/v1/modelsand with the 585K-token session in go: deepseek-v4.1-flash image rejection bricks sessions ("image input is not available on this engine") #61827.cached_tokens: 640) took 111 s to produce its first message. The client pays twice: seconds to learn "no", then ~2 minutes if it ever gets a "yes".cached_tokenswas 640 out of 486,795, i.e. essentially no reuse. That is why "retry shortly (after 5 s)" produces a burst of identical failures instead of recovery.Asks for the Go service
Retry-After(429 / 503) together with a stable machine-readablecodeforprefill_cap_refused/ttft_admission_refused/overloaded. Today the only signal is English prose, and per the mock test above a non-429 4xx bypasses client retry entirely.x-opencode-sessionalways lands on the same cell, consider failing over on admission failures, or expose a way to re-pin a conversation.Happy to extend the size sweep or attach raw response headers /
x-opencode-log-idvalues if that helps.fix(routing): a failing worker model retries once in a forked session…