Skip to content

bash tool hangs when command spawns background child processes #20902

Description

@tidyinfo

Bug Description

The bash tool hangs indefinitely (until the default 2-minute timeout kicks in) when a command spawns a background child process, such as:

  • npm run build &
  • nohup some_cmd &
  • bash -c "sleep 10 &"

During the hang, the session appears completely stuck and the LLM cannot proceed.

Root Cause

In packages/opencode/src/effect/cross-spawn-spawner.ts, the spawner uses the close event to determine when a process has finished:

proc.on("close", (...args) => {
  Deferred.doneUnsafe(signal, Exit.succeed(exit ?? args))
})

Node.js fires close only after all stdio streams are closed. When a shell spawns a background child (e.g., bash -c "sleep 10 &"), the child inherits stdout/stderr pipe file descriptors. The shell process exits immediately, but close won't fire until the background process also exits and releases those pipes.

I verified this behavior:

Command exit fires close fires
echo hello 1ms 1ms
bash -c "sleep 10 &" 1ms 10004ms
bash -c "nohup sleep 10 >/dev/null 2>&1 &" 2ms 7ms

For a long-running daemon, close would never fire at all.

Proposed Fix

Replace close with exit as the completion signal in the spawn callback. The exit event fires as soon as the spawned process terminates, regardless of inherited pipe descriptors.

Environment

  • opencode version: latest (dev branch)
  • OS: Linux (WSL2) / Windows
  • Node.js / Bun: both affected

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions