Repository navigation
Description
Verify latest release
- I verified that the issue exists in the latest pnpm release (12.15.0)
pnpm version
12.15.0
Which area(s) of pnpm are affected?
Store
Link to the code that reproduces this issue
https://github.com/rubnogueira/pnpm-gvs-built-row
Reproduction steps
- Clone https://github.com/rubnogueira/pnpm-gvs-built-row.
- Run
bash repro.sh. It needs network access to GitHub and the npm registry, and a C++ toolchain fornode-gyp.
The repo has two projects that share one store (storeDir: ../store) with enableGlobalVirtualStore: true. Both depend on the same commit of a native addon from GitHub, and both allow its build:
# project-a/pnpm-workspace.yaml (project-b is the same, but nan: 2.26.2)
storeDir: ../store
cacheDir: ../cache
enableGlobalVirtualStore: true
overrides:
nan: 2.27.0
allowBuilds:
node-expat@https://codeload.github.com/xmppo/node-expat/tar.gz/78e559baa908942097330f7967dfbf623ebc2529: true{ "dependencies": { "node-expat": "github:xmppo/node-expat#78e559baa908942097330f7967dfbf623ebc2529" } }The only difference is the nan override. It gives node-expat a different dependency, so project-b needs a new slot for the same node-expat commit. repro.sh clears the store, installs project-a, then project-b, and checks for node_modules/node-expat/build/Release/*.node:
project-a: built
project-b: NOT BUILT
Describe the Bug
pnpm builds a git-hosted dependency only in the first global virtual store slot it creates for that dependency. A later slot for the same commit is linked without running the build. pnpm exits 0 and prints no warning; the app fails at runtime when it loads the addon.
What we found:
- The two slots are
store/v11/links/@/node-expat/2.4.1/<hash-a>and…/<hash-b>. - The store index (
store/v11/index.db, tablepackage_index) has one row per git-hosted package, not one per slot:https://codeload.github.com/xmppo/node-expat/tar.gz/78e559b…\tbuilt. pnpm seems to read this row as "already built" and skips the build for every later slot. - These do not build the new slot:
pnpm rebuild,pnpm install --force,sideEffectsCache: false, and deleting only the slot folder before an install. - Deleting the slot folder and the
\tbuiltrow makes the next install build the slot. pnpm then writes the row again, so the next new slot has the same problem. - A
git+file://dependency fails the same way (row keygit+file://…#<commit>\tbuilt). Afile:tarball with an install script is built in both slots, so the problem is specific to git-hosted dependencies.
We hit this in a monorepo whose Docker dev container keeps the store in a volume. A dependency change gave a GitHub-hosted native addon a new slot, and the service crashed at startup. Our workaround runs after each install: it finds slots without the build output, deletes them and the \tbuilt row, and installs again.
Possibly related: #16642 (a later install trusts a broken slot).
Expected Behavior
pnpm runs the build of an allowed git-hosted dependency in every new slot, as it does for the first one:
project-a: built
project-b: built
Which Node.js version are you using?
24.22.0 (also seen with 24.22.1)
Which operating systems have you used?
- macOS
- Windows
- Linux
If your OS is a Linux based, which one it is?
Debian 13 (x86_64); also seen in a Docker container
Activity
github-actions commentedon Oct 22, 2026
@rubnogueira, are you planning to open a pull request for this? If so, reply here and a maintainer will assign the issue to you, so nobody else starts on the same fix.
rubnogueira commentedon Oct 22, 2026
Yes
rubnogueira commentedon Oct 22, 2026
#17231 fixes this. It covers the whole issue.
The cause is the store-index row the git fetcher writes. Its
requiresBuildrecorded whether the package neededprepare, not whether it has install scripts.node-expathas aninstallscript and noprepare, so the row said "no build". Later installs trusted the row and skipped the build in every new slot. The same happened when reinstalling into a freshnode_modulesfrom a warm store.The PR stores
requiresBuildfrom the package's files, as for any other package. It also re-derives the value for rows already in a store, so existing stores, such as one kept in a Docker volume, are fixed without clearing the store or deleting the\tbuiltrow. pnpm 11 computes this correctly and is not affected.Written by an agent (Claude Code, claude-opus-5-5).
fix(git-fetcher): build a git dependency in every slot it is linked into
fix(git-fetcher): build a git dependency in every slot it is linked i…
Update pnpm to v12.16.1 (#2164)