Repository navigation
Every script run without a terminal starts a second sh since 12.7.0 and 11.28.0 #16489
Description
Verify latest release
- I verified that the issue exists in the latest pnpm release
pnpm version
12.8.2 and 11.28.3. Last good: 12.6.0 and 11.27.1. First bad: 12.7.0 and 11.28.0.
Which area(s) of pnpm are affected? (leave empty if unsure)
CLI
Link to the code that reproduces this issue or a replay of the bug
No response
Reproduction steps
Run pnpm without a controlling terminal, as CI, IDE task runners and agents do:
mkdir ws && cd ws
echo '{"name":"root","private":true}' > package.json
printf 'packages:\n - "packages/*"\n' > pnpm-workspace.yaml
# Records the watchdog shells whose parent is the pnpm running the script ($1).
cat > spy.sh <<'SPY'
ps -A -o pid= -o ppid= -o args= | awk -v pnpm="$1" '$2 == pnpm && /INT TERM HUP/ { print $1 }' >> "$(dirname "$0")/watchdogs.log"
SPY
for i in $(seq 1 50); do
mkdir -p packages/p$i
echo "{\"name\":\"p$i\",\"version\":\"1.0.0\",\"scripts\":{\"noop\":\"true\",\"spy\":\"sh ../../spy.sh \$PPID\"}}" > packages/p$i/package.json
done
pnpm -r run spy </dev/null >/dev/null 2>&1
sort -u watchdogs.log | wc -l # watchdog shells started for 50 scripts
/usr/bin/time -l pnpm -r run noop </dev/null >/dev/null 2>&1 # macOS: "instructions retired"Results on macOS arm64 (instructions retired by the pnpm process, median of 5 runs, 50-entry PATH):
| pnpm | watchdog shells for 50 scripts | instructions |
|---|---|---|
| 12.6.0 | 0 | 547M |
| 12.7.0 | 50 | 873M |
| 12.8.2 | 50 | 793M |
| 11.27.1 | 0 | 3.91G |
| 11.28.3 | 50 | 5.31G |
Describe the Bug
Since #15564, pnpm starts a watchdog sh (trap '' INT TERM HUP; read -r _ || kill -9 -$1) next to every script that runs in a process group of its own. A script gets its own group whenever pnpm has no controlling terminal. In pnpm 12, every script of a concurrent recursive run gets one too. So pnpm -r run over N projects starts 2N shells, and every pnpm run, pnpm exec and lifecycle script in CI pays an extra process spawn.
On macOS the cost grows with PATH length, because the bare sh is looked up on PATH for every spawn. With a 96-entry PATH, pnpm -r run noop over 50 projects costs 1.17G instructions on current main, against 0.59G with one watchdog.
The guarantee from #15564 (a script's process group dies when pnpm is killed) does not need a shell per script.
Expected Behavior
One process per script, as in 12.6.0 and 11.27.1, while a script's process group still ends when pnpm is killed.
Which Node.js version are you using?
24.21.0
Which operating systems have you used?
- macOS
- Windows
- Linux
If your OS is a Linux based, which one it is? (Include the version if relevant)
Measured on macOS only. The same code path runs on Linux; Windows uses a Job Object and has no watchdog.
Contributing a fix
- I am working on a fix
Written by an agent (Claude Code, Opus 5.5).
Activity
altaywtf commentedon Oct 1, 2026
I'm working on a fix for this.
Written by an agent (Claude Code, Opus 5.5).
altaywtf commentedon Oct 1, 2026
A fix is ready for review in #16490. CI is green.
Written by an agent (Claude Code, Opus 5.5).
perf: watch every script's process group with one watchdog (#16490)
fix(deps): update dependencias no-major (#23)
chore(deps): update pnpm to v12.9.0
chore(deps): update pnpm to v12.9.0
chore(deps): update pnpm to v12.9.0
chore(deps): update pnpm to v12.9.0
chore(deps): update pnpm to v12.9.0