Repository navigation
Description
Verify latest release
- I verified that the issue exists in the latest pnpm release
pnpm version
12.11.2 (the latest dist-tag on 2026-10-11). The code cited below is unchanged at v12.12.1 and on main at 77186e6.
Which area(s) of pnpm are affected? (leave empty if unsure)
CLI, Operating System (Windows, MacOS, Linux)
Link to the code that reproduces this issue or a replay of the bug
https://github.com/antst/dashi/actions/runs/38143574787/job/114482195699 (GitHub-hosted macos-26-arm64 runner; the complete command log is the job's install-macos-latest-G-pnpm12 artifact)
Reproduction steps
On macOS, with Node.js and npm:
T="$(mktemp -d)"; mkdir "$T/user" "$T/tools" "$T/pnpm-global"
export HOME="$T/user" PNPM_HOME="$T/pnpm-global" SHELL=/bin/bash
npm install --global --prefix "$T/tools" pnpm@12.11.2
export PATH="$T/tools/bin:$PATH"
pnpm setup
. "$HOME/.bashrc"
pnpm --versionThese are the steps of the CI job linked above, with these differences: the job's $T was a directory under the runner's temp directory, its first command after setup was pnpm add -g @deepseek-ai/dsh@0.2.1-alpha.2 rather than pnpm --version, and it also pointed XDG_* and npm's cache, userconfig and prefix into the same tree. The failure is in the launcher's exec, before pnpm itself starts. On Linux this snippet, run verbatim, ends by printing 12.11.2.
The consequence can be reproduced on Linux without a Mac by running setup's self-install step by hand against the bin directory, which is the directory macOS makes setup use (run verbatim on Ubuntu 24.04, Node.js 25.9.0, npm 11.12.1):
T="$(mktemp -d)"; mkdir "$T/user" "$T/tools" "$T/pnpm-global"
export HOME="$T/user" PNPM_HOME="$T/pnpm-global"
npm install --global --prefix "$T/tools" pnpm@12.11.2
export PATH="$T/tools/bin:$PATH"
echo '{"name":"pnpm","version":"12.11.2","type":"module","bin":{"pnpm":"pnpm","pn":"pnpm"},"files":["pnpm","dist/"]}' > "$T/tools/bin/package.json"
PATH="$PNPM_HOME/bin:$PATH" pnpm add -g --ignore-scripts "file:$T/tools/bin"
rm "$T/tools/bin/package.json"
"$PNPM_HOME/bin/pnpm" --version; echo "exit=$?"
ls -A "$PNPM_HOME"/global/v11/*/node_modules/pnpm/The install prints + pnpm file:../../../../tools/bin, the same line as on macOS. The launcher then fails with the following, where <tmp> stands for $T: <tmp>/pnpm-global/bin/pnpm: 82: exec: <tmp>/pnpm-global/bin/../global/v11/82859147b4fec5e788f016e5ca7f0a52c473a92cd2037e4c8bdc7029c86b60f3/node_modules/pnpm/pnpm: not found and exit=127 (the launcher is a /bin/sh script, here dash), and the installed node_modules/pnpm/ contains only package.json and node_modules.
Describe the Bug
On macOS (26.6.2, arm64; Node.js 22.23.2, npm 10.9.8) pnpm setup exits 0 and prints the following. As in the steps above, <tmp>/tools is the npm prefix, <tmp>/pnpm-global is PNPM_HOME and <tmp>/user is HOME; only that temporary prefix is shortened.
Installing pnpm CLI globally from <tmp>/tools/bin
.../global/v11/f26-18dd7cebb67cf618-0 | Progress: resolved 1, reused 0, downloaded 0, added 0
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: <tmp>/pnpm-global/store/v11
Virtual store is at: ../pnpm-global/global/v11/f26-18dd7cebb67cf618-0/node_modules/.pnpm
.../global/v11/f26-18dd7cebb67cf618-0 | Progress: resolved 1, reused 0, downloaded 0, added 1, done
dependencies:
+ pnpm file:../../../../tools/bin
Done in 112ms using pnpm v12.11.2
Created <tmp>/user/.bashrc
The following configuration changes were made:
export PNPM_HOME='<tmp>/pnpm-global'
case ":$PATH:" in
":$PNPM_HOME/bin:"*) ;;
*) export PATH="$PNPM_HOME/bin:$PATH" ;;
esac
To start using pnpm, run:
source <tmp>/user/.bashrc
After sourcing that file, the first pnpm command (pnpm add -g @deepseek-ai/dsh@0.2.1-alpha.2 in the job) exits with status 126:
<tmp>/pnpm-global/bin/pnpm: line 82: <tmp>/pnpm-global/bin/../global/v11/82859147b4fec5e788f016e5ca7f0a52c473a92cd2037e4c8bdc7029c86b60f3/node_modules/pnpm/pnpm: No such file or directory
<tmp>/pnpm-global/bin/pnpm: line 82: exec: <tmp>/pnpm-global/bin/../global/v11/82859147b4fec5e788f016e5ca7f0a52c473a92cd2037e4c8bdc7029c86b60f3/node_modules/pnpm/pnpm: cannot execute: No such file or directory
The generated launcher comes first on PATH, so every later pnpm command fails, while the npm-installed binary still works by its full path (<tmp>/tools/bin/pnpm --version printed 12.11.2 in the same job).
On Linux the same steps work. Setup reports the real package directory (Installing pnpm CLI globally from <tmp>/tools/lib/node_modules/pnpm, + pnpm file:../../../../tools/lib/node_modules/pnpm), downloads @pnpm/exe.linux-x64@12.11.2, and the generated launcher prints 12.11.2.
What the source at v12.11.2 shows:
current_executableisstd::env::current_exe(pnpm/crates/executor/src/pnpm_executable.rs:3-4), which on macOS is the path pnpm was started through. npm's global bin entry<prefix>/bin/pnpmis a symlink to../lib/node_modules/pnpm/pnpm.setupuses that path's parent as the package directory (pnpm/crates/cli/src/cli_args/setup.rs:62-68and:99-116).<prefix>/binhas nopackage.json, so setup writes its standalone manifest (:169-177) there, runspnpm add -g --ignore-scripts file:<prefix>/bin(:138-142) and removes the manifest again (:146).- The package installed from that directory has no
pnpmfile (see the Linux run above), but the launcher that execsnode_modules/pnpm/pnpmis still generated. We did not look into why the symlinkedpnpmentry is left out of the installed copy.
This looks like the same root cause as #15694 and #15691, which #15695 and #15692 fixed for two other users of current_exe.
For context, pnpm 11.18.0 in the same job layout also reported Installing pnpm CLI globally from <tmp>/tools/bin, on macOS and on Linux, then warned Failed to create bin at <tmp>/pnpm-global/bin/pnpm. ENOENT: no such file or directory, open …, and the later pnpm commands of that job worked. We did not check whether a launcher existed there, so we cannot say that 11.x produced a working one; that is why this is a plain bug report and not a regression report.
Workaround: do not run pnpm setup; keep using the npm-installed pnpm and set the global bin directory by hand (pnpm config set global-bin-dir <dir>, with <dir> on PATH). The same macOS job passes that way: https://github.com/antst/dashi/actions/runs/38152725106 (install-layouts-macos / G-pnpm12 / macos-latest).
We tested only an npm install with --prefix. We did not test a default-prefix npm install -g pnpm or a Homebrew install; we expect any install where pnpm is reached through a symlink to take the same path.
Expected Behavior
pnpm setup installs from the real package directory, as it does on Linux, so that $PNPM_HOME/bin/pnpm runs. Failing that, it should exit with an error rather than exit 0 and leave a launcher that cannot run.
Suggested fix: canonicalize the executable path before taking its parent in install_cli_globally (setup.rs:99-101), for example with dunce::canonicalize as #15695 and #15692 did.
Which Node.js version are you using?
22.23.2 (macOS); 25.9.0 (Linux by-hand run)
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)
Ubuntu 24.04. pnpm setup itself works there; Linux was used for the control run and the by-hand reproduction.
Contributing a fix
- I am working on a fix
Activity
zkochan commentedon Oct 11, 2026
Thanks for the detailed report. #16857 fixes this:
pnpm setupnow resolves the executable through symlinks before choosing the directory to install from, so an npm install on macOS installs from<prefix>/lib/node_modules/pnpmas on Linux. The same PR fixes pnpm 11, whereprocess.argv[1]kept the<prefix>/bin/pnpmsymlink path; an npm-installed pnpm 11 now skips the self-install it could not complete. It covers the whole issue.Written by an agent (Claude Code, claude-opus-5-5).
fix(setup): resolve the pnpm executable through symlinks (pnpm#16857)