Skip to content

core: shell commands run by Git Bash keep running after timeout on Windows #57311

Open

Description

@theshasha

Description

On Windows, a timed out (or aborted) shell command is killed with taskkill /pid <shell> /T /F, which walks the Windows parent/child tree. With Git Bash (MSYS2/Cygwin) that tree is broken: bash starts commands with fork + exec, and on Windows the exec'd program is a new process whose parent (the forked child) exits right away. The program ends up with a dead parent PID, outside the tree, so taskkill reports success and the program keeps running.

Only commands bash forks are affected: anything before ;, pipelines, subshells, background jobs, scripts. The last command of the -c string is exec'd by bash without a fork and still gets killed, so cd x && npm run dev is fine but npm i; npm run dev or npm run dev | tee log is not. Leftovers keep ports and file locks. Might be what #37007 sees on Windows.

The orphans are still in bash's msys process group (checked with msys ps -l), so killing that group with the msys kill -9 -<pgid> before the taskkill would catch them; a Job Object would too.

Plugins

none

OpenCode version

current dev

Steps to reproduce

import { spawn, execSync } from "child_process"
const p = spawn("C:/Program Files/Git/bin/bash.exe", ["-c", "sleep 300; echo done"], { stdio: "ignore" })
setTimeout(() => {
  execSync(`taskkill /pid ${p.pid} /T /F`) // what OpenCode does on timeout
  setTimeout(() => console.log(execSync('tasklist /fi "imagename eq sleep.exe"').toString()), 1000)
}, 1000)
// sleep.exe is still listed; with "sleep 300" alone it is gone

Process tree while it runs:

node
└─ Git\bin\bash.exe
   └─ Git\usr\bin\bash.exe
sleep.exe 300            <- parent PID belongs to an already exited process

Operating System

Windows 11 (22621), Git for Windows 2.52.0

Terminal

n/a (shell tool)

Activity

  1. opencode-agent commented on Oct 20, 2026

    @opencode-agent
    Contributor

    Thanks for the detailed report and the standalone script. Our reproduction sandbox runs Linux, so we can't recreate the Windows + Git Bash process tree that this depends on. A maintainer with a Windows machine will need to confirm it.

    On the latest dev (9d90d89), the Windows path in killGroup (packages/util/src/cross-spawn-spawner.ts) still runs only taskkill /pid <pid> /T /F. It doesn't kill the msys process group or use a Job Object, so what you describe very likely still applies.

    Related issues:

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

Metadata

Metadata

Assignees

No one assigned

    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