Verify latest release
pnpm version
v11
Which area(s) of pnpm are affected? (leave empty if unsure)
Package manager compatibility
Link to the code that reproduces this issue or a replay of the bug
No response
Reproduction steps
Full disclosure: I used AI to help debug this issue and write the bug report but I have read the report and verified the details myself. I have also confirmed the proposed workaround (installing Node 24 first) fixes the issue for me on GitHub Actions.
# @pnpm/exe@11.0.6 — broken
mkdir -p /tmp/exe && curl -sL https://registry.npmjs.org/@pnpm/exe/-/exe-11.0.6.tgz | tar -xzf - -C /tmp/exe
ls -l /tmp/exe/package/dist/node-gyp-bin/node-gyp
# -rw-r--r-- <-- no execute bit
# pnpm@11.0.6 — correct
mkdir -p /tmp/pnpm && curl -sL https://registry.npmjs.org/pnpm/-/pnpm-11.0.6.tgz | tar -xzf - -C /tmp/pnpm
ls -l /tmp/pnpm/package/dist/node-gyp-bin/node-gyp
Three files in @pnpm/exe's dist/ lose their execute bit relative to the regular pnpm npm package:
| Path |
pnpm@11.0.6 |
@pnpm/exe@11.0.6 |
dist/node-gyp-bin/node-gyp |
0755 |
0644 ❌ |
dist/node-gyp-bin/node-gyp.cmd |
0755 |
0644 ❌ |
dist/node_modules/node-gyp/bin/node-gyp.js |
0755 |
0644 ❌ |
Every other file in dist/ has matching modes between the two packages, so the breakage is scoped specifically to the node-gyp shims.
End-to-end repro via pnpm/action-setup@v6 on GitHub Actions
pnpm/action-setup@v6 falls back to @pnpm/exe whenever the runner's system Node is < 22.13 (see run.ts). On ubuntu-latest (system Node 20.x at the time of writing), this means any project with a native module whose install script invokes node-gyp rebuild fails with:
.../node_modules/<pkg> install: sh: 1: node-gyp: Permission denied
[ELIFECYCLE] Command failed.
…because pnpm prepends dist/node-gyp-bin/ to the build script's PATH, and the shim there isn't executable.
Workaround for affected users: install Node ≥ 22.13 before pnpm/action-setup so the action takes the non-standalone path and uses the regular pnpm package. Or chmod +x the three files post-install.
Describe the Bug
@pnpm/exe@11.x packs dist/node-gyp-bin/node-gyp, dist/node-gyp-bin/node-gyp.cmd, and dist/node_modules/node-gyp/bin/node-gyp.js with mode 0644 instead of 0755. The same files in the regular pnpm npm package are correctly 0755. Any code path that exec's these shims (most importantly: a package's install script that calls node-gyp rebuild while pnpm has put dist/node-gyp-bin/ on PATH) fails with Permission denied.
This appears to be a v11 regression: @pnpm/exe@10.x did not ship a dist/ tree at all (its layout was just a single pnpm binary plus prepare/setup scripts), so this class of breakage couldn't occur. The reorganized @pnpm/exe@11 layout that bundles the full dist/ is what introduced the affected files — and they shipped with wrong modes.
The packaging defect very likely shares its root cause with #11398 (the fs.cpSync invocation in pnpm/artifacts/exe/scripts/build-artifacts.ts), since both involve dist/ content being staged for the @pnpm/exe artifact and ending up materially different from the source. #11398 was about symlink targets not being preserved verbatim; this one is about file modes being lost. A regression check that asserts mode & 0o111 on every file under dist/node-gyp-bin/ (and on dist/node_modules/node-gyp/bin/node-gyp.js) when packing @pnpm/exe would catch both classes.
Expected Behavior
@pnpm/exe@11.x should pack the three node-gyp shims with mode 0755, matching the regular pnpm package. Native modules whose install scripts invoke node-gyp rebuild should work under pnpm/action-setup@v6's standalone path identically to the non-standalone path.
Which Node.js version are you using?
Any version < 22.13
Which operating systems have you used?
If your OS is a Linux based, which one it is? (Include the version if relevant)
Ubuntu
Verify latest release
pnpm version
v11
Which area(s) of pnpm are affected? (leave empty if unsure)
Package manager compatibility
Link to the code that reproduces this issue or a replay of the bug
No response
Reproduction steps
Full disclosure: I used AI to help debug this issue and write the bug report but I have read the report and verified the details myself. I have also confirmed the proposed workaround (installing Node 24 first) fixes the issue for me on GitHub Actions.
Three files in
@pnpm/exe'sdist/lose their execute bit relative to the regularpnpmnpm package:pnpm@11.0.6@pnpm/exe@11.0.6dist/node-gyp-bin/node-gyp07550644❌dist/node-gyp-bin/node-gyp.cmd07550644❌dist/node_modules/node-gyp/bin/node-gyp.js07550644❌Every other file in
dist/has matching modes between the two packages, so the breakage is scoped specifically to the node-gyp shims.End-to-end repro via
pnpm/action-setup@v6on GitHub Actionspnpm/action-setup@v6falls back to@pnpm/exewhenever the runner's system Node is < 22.13 (seerun.ts). Onubuntu-latest(system Node 20.x at the time of writing), this means any project with a native module whose install script invokesnode-gyp rebuildfails with:…because pnpm prepends
dist/node-gyp-bin/to the build script's PATH, and the shim there isn't executable.Workaround for affected users: install Node ≥ 22.13 before
pnpm/action-setupso the action takes the non-standalone path and uses the regularpnpmpackage. Orchmod +xthe three files post-install.Describe the Bug
@pnpm/exe@11.xpacksdist/node-gyp-bin/node-gyp,dist/node-gyp-bin/node-gyp.cmd, anddist/node_modules/node-gyp/bin/node-gyp.jswith mode0644instead of0755. The same files in the regularpnpmnpm package are correctly0755. Any code path that exec's these shims (most importantly: a package'sinstallscript that callsnode-gyp rebuildwhile pnpm has putdist/node-gyp-bin/on PATH) fails withPermission denied.This appears to be a v11 regression:
@pnpm/exe@10.xdid not ship adist/tree at all (its layout was just a singlepnpmbinary plus prepare/setup scripts), so this class of breakage couldn't occur. The reorganized@pnpm/exe@11layout that bundles the fulldist/is what introduced the affected files — and they shipped with wrong modes.The packaging defect very likely shares its root cause with #11398 (the
fs.cpSyncinvocation inpnpm/artifacts/exe/scripts/build-artifacts.ts), since both involvedist/content being staged for the@pnpm/exeartifact and ending up materially different from the source. #11398 was about symlink targets not being preserved verbatim; this one is about file modes being lost. A regression check that assertsmode & 0o111on every file underdist/node-gyp-bin/(and ondist/node_modules/node-gyp/bin/node-gyp.js) when packing@pnpm/exewould catch both classes.Expected Behavior
@pnpm/exe@11.xshould pack the three node-gyp shims with mode0755, matching the regularpnpmpackage. Native modules whose install scripts invokenode-gyp rebuildshould work underpnpm/action-setup@v6's standalone path identically to the non-standalone path.Which Node.js version are you using?
Any version < 22.13
Which operating systems have you used?
If your OS is a Linux based, which one it is? (Include the version if relevant)
Ubuntu