Skip to content

[Bug]: Bash tool hangs on fast-exiting processes and locks database on massive output #21000

@vhqtvn

Description

@vhqtvn

Description

OpenCode Backend Bug: Tool Execution Hangs and Event Loop Blockage

Bug Description

The OpenCode backend experiences two severe stability issues when executing the bash tool:

  1. Indefinite Hangs (Ghost Processes): When a fast-exiting command (like jq, echo, or commands that crash instantly) is executed, the session sometimes hangs permanently. The tool remains in the running state in the UI indefinitely, even though the underlying OS process has already terminated.
  2. Event Loop Blockage (database is locked): When a command emits thousands of lines of output very quickly (e.g., npm install, a large grep, or cat on a massive file), the backend Node.js process chokes, leading to SQLiteError: database is locked exceptions. This drops events and causes the session to hit the 15-second heartbeat timeout.

Root Causes

  1. Race Condition in CrossSpawnSpawner: CrossSpawnSpawner relies strictly on the spawn event to resolve the Effect promise. If a process exits so fast that the spawn event is omitted or misordered by the OS/Node bindings, the resume() callback is never called, leaving the execution promise blocked forever.
  2. Synchronous Metadata Writes: The stream processor (Stream.runForEach) invokes ctx.metadata(...) for every single chunk emitted by the process stdout/stderr. This queues thousands of synchronous db.insert().run() calls on the main thread, locking the database and completely starving the event loop. Furthermore, when the process does exit, the background stream fiber is instantly interrupted, which silently drops any output chunks still buffered in memory.

Steps to Reproduce

Issue 1: Indefinite Hangs

  1. Dispatch multiple fast-exiting tools at once, or run a single incredibly fast tool like jq '{test: 1}'.
  2. Notice that randomly, the UI gets stuck on "running command".
  3. Check ps aux | grep jq — the process is dead, but the backend is still waiting.

Issue 2: DB Locking and Event Loop Starvation

  1. Run a command that outputs massive amounts of text instantly, e.g., cat /dev/urandom | head -n 100000 | base64 or find /.
  2. Watch the logs fill with unhandled SQLiteError: database is locked.
  3. The UI will eventually stall and the session will crash or timeout.

Expected Behavior

  • Fast-exiting processes should reliably resolve their execution promise regardless of event ordering.
  • High-volume output commands should throttle their metadata updates (e.g., every 250ms) to avoid locking the single-writer SQLite database and choking the Node event loop.
  • The stream fiber should fully drain its buffered output before completing the tool execution, ensuring no trailing output is truncated.

OpenCode version

1.3.13

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingcoreAnything pertaining to core functionality of the application (opencode server stuff)perfIndicates a performance issue or need for optimization

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions