Description
SessionProcessor.process() can deadlock or leave sessions in a permanently running state in two cases:
- The stream loop uses
for await (const value of stream.fullStream). If abort fires while iter.next() is waiting on a stuck tool result, iteration can block indefinitely.
- Cleanup-time
Snapshot.patch() is outside the main error boundary. If it throws, message finalization can be skipped, leaving sessions/tool parts stuck as running.
A related symptom is doom-loop permission prompts blocking cancellation when they are awaited without racing abort.
Plugins
None
OpenCode version
1.3.3 (also observed on dev as of 2026-03-30)
Steps to reproduce
- Start a session that triggers a long-running or hanging tool call.
- Cancel while the model stream is waiting for tool output.
- Observe session remains in cancelling/running state.
- Separately, force
Snapshot.patch() failure during cleanup (for example by invalidating git state) and observe finalization is skipped.
Screenshot and/or share link
N/A
Operating System
macOS 15.4.1 (repro also seen on Linux CI)
Terminal
Ghostty
Description
SessionProcessor.process()can deadlock or leave sessions in a permanently running state in two cases:for await (const value of stream.fullStream). If abort fires whileiter.next()is waiting on a stuck tool result, iteration can block indefinitely.Snapshot.patch()is outside the main error boundary. If it throws, message finalization can be skipped, leaving sessions/tool parts stuck as running.A related symptom is doom-loop permission prompts blocking cancellation when they are awaited without racing abort.
Plugins
None
OpenCode version
1.3.3 (also observed on dev as of 2026-03-30)
Steps to reproduce
Snapshot.patch()failure during cleanup (for example by invalidating git state) and observe finalization is skipped.Screenshot and/or share link
N/A
Operating System
macOS 15.4.1 (repro also seen on Linux CI)
Terminal
Ghostty