Description
The TUI freezes and becomes unresponsive when the LLM provider stream errors out mid-flight with a "fetch failed" error. The UI enters a waiting state with no recovery path — no timeout fires, and the interface stays frozen indefinitely while the process continues to consume ~31% CPU in a render loop.
Steps to Reproduce
- Start opencode with an LLM provider that requires a network connection
- Send a message to the agent
- Have the network connection drop or the provider return an error mid-stream
- Observe: the UI freezes and never recovers
Expected Behavior
The UI should detect the stream failure and display an error, allowing the user to retry or exit cleanly.
Actual Behavior
- TUI hangs indefinitely — no error displayed, no way to recover without killing the process
- Process stays alive consuming ~31% CPU (
stat: Rl+)
- Main thread blocked on
ep_poll (epoll waiting for I/O that never arrives)
- Log shows the stream error was recorded, but the UI never unblocks
Log Evidence
level=ERROR message="stream error" providerID=zcode modelID=claude-sonnet-4-6
agent=title error.error.type=api_error error.error.message="fetch failed"
level=ERROR message="stream error" providerID=zcode modelID=claude-sonnet-4-6
agent=build error.error.type=api_error error.error.message="fetch failed"
The title agent failed at T+0:05, the build agent at T+2:21. After that, the UI was frozen for 5+ hours until manually killed.
Sequence of Events
10:13:10 models.dev fetch → TimeoutError
10:16:40 New session created, user message sent
10:16:45 Title agent stream → "fetch failed"
10:19:06 Build agent stream → "fetch failed"
← UI freezes here, no recovery
Process Snapshot (at hang)
PID STAT %CPU THREADS ELAPSED WCHAN
58867 Rl+ 31.1 33 4:08:31 ep_poll
- 33 threads, most in
futex_wait (normal)
- Main thread:
ep_poll — blocked waiting for I/O event that never fires
- No subprocess leak, no DB lock, SQLite WAL clean
Environment
- opencode version: 1.18.25
- OS: Ubuntu 24.04.4 LTS (Noble Numbat)
- Kernel: 6.8.0-138-generic
- Platform: Linux x86_64
- Node: v24 (Bun runtime)
- Provider: zcode (Claude Sonnet 4.6 proxy)
Suggested Fix
Add a stream-level timeout or watchdog: if a stream has errored and the promise has not resolved within N seconds, surface the error in the UI and unblock the render loop. A Promise.race(stream, timeout) pattern around the provider stream would prevent the indefinite wait.
Description
The TUI freezes and becomes unresponsive when the LLM provider stream errors out mid-flight with a
"fetch failed"error. The UI enters a waiting state with no recovery path — no timeout fires, and the interface stays frozen indefinitely while the process continues to consume ~31% CPU in a render loop.Steps to Reproduce
Expected Behavior
The UI should detect the stream failure and display an error, allowing the user to retry or exit cleanly.
Actual Behavior
stat: Rl+)ep_poll(epoll waiting for I/O that never arrives)Log Evidence
The title agent failed at T+0:05, the build agent at T+2:21. After that, the UI was frozen for 5+ hours until manually killed.
Sequence of Events
Process Snapshot (at hang)
futex_wait(normal)ep_poll— blocked waiting for I/O event that never firesEnvironment
Suggested Fix
Add a stream-level timeout or watchdog: if a stream has errored and the promise has not resolved within N seconds, surface the error in the UI and unblock the render loop. A
Promise.race(stream, timeout)pattern around the provider stream would prevent the indefinite wait.