Repository navigation
chunkTimeout and timeout are silently ignored on the v2 packages/llm provider path #46692
Description
Description
chunkTimeout and timeout are accepted by the provider config schema and documented, but packages/llm never reads them. Providers routed through the v2 native path therefore have no client-side stall bound at all, and the settings fail silently.
Implemented in two places, neither on the v2 path:
packages/core/src/aisdk.ts:78(AI SDK path)packages/opencode/src/provider/provider.ts:1789(v1 path)
Declared and documented:
packages/core/src/v1/config/provider.ts— schema: "If no chunk arrives within this window, the request is aborted."packages/web/src/content/docs/config.mdx— same promisepackages/opencode/test/provider/header-timeout.test.ts— passing test: "chunkTimeout raises a response stream error when SSE body stalls"
Not implemented:
packages/llm/src/providers/azure.tsroutes viaOpenAIResponses.route.with({ id: "azure-openai-responses" })packages/llm/srccontains no timeout application. The onlyTimeoutreference is classification,packages/llm/src/route/executor.ts:319(Cause.isTimeoutError).
Note the schema lives under core/src/v1/config/provider.ts — this looks like a v1-era option that was not carried into packages/llm.
Impact. A half-open or stalled SSE stream is bounded only by Bun's TCP keepalive (src/http/lib.rs set_keep_alive(true, 60) plus hardcoded TCP_KEEPINTVL=1 / TCP_KEEPCNT=10 in packages/bun-usockets/src/bsd.c), so ~70s. If the peer stays alive but stops sending, nothing bounds it at all.
Against a real Azure OpenAI endpoint whose upstream APIM gateway RSTs mid-stream on ~2% of requests, every occurrence costs ~70s of dead time before the retry fires, and the turn surfaces only as Decode error (200 POST ...) — see #42482, whose cited path packages/ai/src/route/executor.ts is now packages/llm/src/route/executor.ts.
Secondary observation. The documented config key appears to be options, but only settings took effect on this build: providers.azure.settings.baseURL redirected the provider, providers.azure.options.baseURL did not. Worth confirming whether the v2 schema and docs disagree.
Steps to reproduce
-
Run a local server that returns 200 with
Content-Type: text/event-stream, sends two valid SSE frames, then holds the socket open and sends nothing further. -
Point a
packages/llm-routed provider at it and set a short chunk timeout:
{
"providers": {
"azure": {
"settings": {
"baseURL": "http://127.0.0.1:8899/openai/v1",
"chunkTimeout": 15000
}
}
}
}opencode run --standalone --model azure/<model> "hi"
Expected: request aborts at ~15s with a stream error.
Actual: no abort. I killed it externally at 100s. Same result with "timeout": 20000 (killed at 80s). baseURL in the same settings block did take effect, so the block is parsed and applied.
OpenCode version
0.0.0-beta-18743
Operating System
macOS 26.5.2 (Darwin arm64)
Terminal
Ghostty
Activity
holny commentedon Sep 2, 2026
I'd like to take this. Confirmed on current
v2:settingslands in a loose record and the HTTP SSE path never applies a stall bound — the WebSocket channel has an idle timeout and the aisdk path haswrapSSE, HTTP has neither. Plan: addchunkTimeouttoHttpOptions, apply it as an element-gap timeout on the response stream in the HTTP transport, and thread it through provider settings so the configured key finally takes effect.holny commentedon Sep 9, 2026
Heads-up: the PR for this issue (#46802) was accidentally closed earlier today - its head fork got deleted unintentionally, which force-closed it. Re-filed as #48158 with the same commits. Sorry for the noise.
BajajGirik commentedon Sep 19, 2026
Additional data point from OpenCode V2. The native OpenAI path still produced an unbounded stalled turn on the current release.
Environment
2.0.8,latestchannelopenai/gpt-5.6-sol, variantmediumTERM=xterm-256color,COLORTERM=truecolor/bin/zshses_f490c3b66ffeSncEFUrgZgaS2hObserved state
The session stopped making progress but remained in the process-local active registry:
{ "ses_f490c3b66ffeSncEFUrgZgaS2h": { "type": "running" } }At the same time:
opencode service statusreturned a live local service.opencode api get /api/inforeturned version2.0.8and a live PID.outcome: "succeeded"from its earlier idle boundary.2026-09-19T00:01:42Zand had notime.completed,finish, orerrorwhen inspected more than eight minutes later.2026-09-19T00:02:01Z, followed by an empty text part. No finish event arrived.This looks consistent with the native
packages/llmstream path not applying a chunk timeout. It is also a real-release confirmation for the failure that #49229 is intended to fix.felixzsh commentedon Sep 26, 2026
Large-N field data from a real release session: the missing stall bound is hit in ~0.9% of turns, and manual interruption is the only thing that ends them.
Environment
2.0.18(latestchannel), Linux x64opencode-go(mimo-v2.6-flash,deepseek-v4.1-flash,space-bunny-free,muse-spark-1.3-contributor),opencode(deepseek-v4.1-flash,space-bunny-free),openai(gpt-6-sol,gpt-6-luna-fast,gpt-5.6-sol,gpt-5.6-sol-fast,gpt-5.6-terra)plan-auto-buildhook (no provider/stream involvement)chunkTimeout/timeout: not set in config — I read the issue as "these settings are silently ignored", so to be precise: this is not a repro of the config key failing, it is evidence that no client-side stall bound exists by default either.Data
Counted from
session_messagerows in~/.local/share/opencode/opencode.db, over all assistant turns with atime.completed:time.streamedis null (not one token emitted)These are turns where the request was accepted and
time.createdwas written, but nostreamedtimestamp ever arrived. They sit there until an interrupt is sent. Only 4 of the 47 ever ended on their own (network/TCP path); the other 43 waited for a human, including one that ran to 830s — far past the ~70s keepalive bound described above.Because this spans 11 models across 3 providers, it does not look model- or provider-specific — consistent with the defect being in the shared
packages/llmstream path rather than in any one upstream.Same-session A/B from today
Two consecutive windows in one session, same codebase, same machine, only the model changed:
The 273s and 101s rows both ended as
"finish":"error", "error":{"type":"aborted","message":"Step interrupted"}withcontent: []— the turn had produced literally nothing when I killed it. Immediately after switching models the same session resumed normally at 14s/turn.Why this is additive
#51291 covers the same missing-reaper shape but from the tool-part side, and the comment above covers a single
gpt-5.6-solturn on2.0.8. This adds: frequency at scale, the fact that it spans 11 models, and confirmation it reproduces on2.0.18with defaults and no provider overrides configured.Happy to pull per-turn timings or the raw rows for a specific window if a repro trace would help #48158.
rekram1-node commentedon Oct 2, 2026
Fixed in #49229, available in v2.0.22.
felixzsh commentedon Oct 2, 2026
Thanks for that but the root cause is not fixed, i just updated to that version and i still see how the agents gets stuck in simple commands por example a simple git add, i see the output of the command but the agent never continues, i know there is a 5 minutes timeout but i had to interrumpt after 2 minutes anyways ...
andrea-lorenzetti commentedon Oct 5, 2026
following this issue because I ran in "sse read timed out" and the suggested way to avoid the problem is to set chunkTimeout to false, but if this value is not used from opencode I am not solving the error.