Uh oh!
There was an error while loading. Please reload this page.
fix: SSE stream hang causing run --format json to hang indefinitely - #24762
fix: SSE stream hang causing run --format json to hang indefinitely#24762bingkxu wants to merge 1 commit into
Conversation
Problem: opencode run --format json hangs indefinitely when the LLM SSE stream silently drops (network interruption or server-side disconnect). The underlying ReadableStream reader.read() Promise never resolves, and no timeout or error handling exists to recover from this state. Root cause: provider.ts sets chunkTimeout from options[chunkTimeout], but no provider configures this value. When undefined, wrapSSE() skips the SSE response entirely (typeof ms !== number check), leaving the raw reader with no idle timeout protection. Fix: 1) provider.ts: default chunkTimeout to 60_000ms (60s). All SSE streams are now wrapped with wrapSSE(), which aborts the reader if no chunk arrives within 60 seconds. Applies to all providers globally. 2) message-v2.ts: map SSE read timed out error to APIError with isRetryable=true, enabling the existing exponential-backoff retry mechanism (2s to 30s cap).
The following comment was made by an LLM, it may be inaccurate: Potential Related PR Found: PR #19116: fix(opencode): reconnect on network disruptions (VPN switch, SSE timeout, connection reset) Why it's related: This PR also addresses SSE timeout and connection reset issues in the opencode project. It deals with similar network disruption scenarios (VPN switches, SSE timeouts, connection resets) that could overlap with the current PR's fix for SSE stream hangs with idle timeouts. Worth verifying if they're addressing the same root cause or if this was a previous attempt at a similar fix. |
rekram1-node
commented
Apr 28, 2026
we intentionally dont set this timeout, causes lots of issues |
bingkxu
commented
Apr 29, 2026
What problems will it cause? Any suggestions in this condition - still hang? |
Issue for this PR
Closes#8002
Type of change
What does this PR do?
When the SSE connection to the LLM provider silently drops (no RST/FIN — common on satellite, mobile, or unstable networks), the
reader.read()Promise in the fetch response body never resolves. Since no idle timeout was configured, the process hangs forever.The root cause:
wrapSSE()inprovider.tsprovides exactly this timeout protection, but it was never activated becausechunkTimeoutdefaulted toundefined(no provider sets it in options).Two changes:
chunkTimeoutto 60s. Every SSE response now gets wrapped with an idle timer that aborts the reader if no data arrives within 60 seconds."SSE read timed out"error toAPIError(isRetryable: true)so the existing exponential-backoff retry kicks in (2s→4s→8s→16s→30s cap, retries until network recovers).How did you verify your code works?
fromErrormapping andretryableclassification)run --format jsonexecuting real build tasks via GLM-5Screenshots / recordings
N/A — backend-only change, no UI impact.
Checklist