Skip to content

pnpm install in a workspace package keeps prompting to remove node_modules when enableGlobalVirtualStore is enabled #12307

Description

@rubnogueira

Verify latest release

  • I verified that the issue exists in the latest pnpm release

pnpm version

11.5.2

Which area(s) of pnpm are affected? (leave empty if unsure)

Store

Link to the code that reproduces this issue or a replay of the bug

https://github.com/rubnogueira/pnpm-repro-sharedlockfile

Reproduction steps

.
├── package.json # { "name": "repro-root", "private": true }
├── pnpm-workspace.yaml
└── libs/common
├── package.json # { "name": "@repro/common", "dependencies": { "is-odd": "3.0.1" } }
└── pnpm-workspace.yaml

pnpm-workspace.yaml (root):

packages:
  - libs/*
enableGlobalVirtualStore: true
sharedWorkspaceLockfile: false

libs/common/pnpm-workspace.yaml (makes the package its own workspace root, with its own lockfile):

  enableGlobalVirtualStore: true

Steps:
rm -rf node_modules libs/common/node_modules pnpm-lock.yaml libs/common/pnpm-lock.yaml
pnpm install # at root — OK
cd libs/common && pnpm install # prompts to remove & recreate node_modules

Describe the Bug

Installation / global virtual store (enableGlobalVirtualStore), post-install build step.

When enableGlobalVirtualStore: true is set, running pnpm install at the workspace root succeeds, but a subsequent pnpm install inside a workspace package prompts:

? The modules directory at ".../libs/common/node_modules" will be removed and
reinstalled from scratch. Proceed? (Y/n)

(In a non-TTY/CI shell the same condition surfaces as ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY.) The prompt comes back every time you install in that package, even though nothing changed.

Expected Behavior

The second pnpm install is a no-op ("Already up to date") — node_modules is already valid and should not be purged.

Actual behavior

pnpm reports a virtual-store mismatch and wants to recreate node_modules:

[ERR_PNPM_UNEXPECTED_VIRTUAL_STORE] Unexpected virtual store location
The dependencies at ".../libs/common/node_modules" are currently symlinked from the virtual store directory at ".../libs/common/node_modules/.pnpm". pnpm now wants to use the virtual store at ".../store/v11/links" ...

Root cause

During a workspace install with enableGlobalVirtualStore, each project's node_modules/.modules.yaml is written twice, with conflicting virtualStoreDir values:

  1. The install/link step writes the correct GVS value virtualStoreDir = /links — extendInstallOptions (installing/deps-installer/src/install/extendInstallOptions.ts) sets virtualStoreDir to /links when GVS is enabled.
  2. The post-install build pass — buildProjects (building/after-install/src/index.ts), run as the per-project rebuild during a workspace install — calls getContext() and rewrites .modules.yaml. Its options come from extendBuildOptions (building/after-install/src/extendBuildOptions.ts), which — unlike extendInstallOptions — never sets virtualStoreDir for GVS. So getContext falls back to the per-project default node_modules/.pnpm and the rewrite overwrites the correct value the install step recorded.

The next install in that project recomputes /links, compares it to the recorded node_modules/.pnpm, fails checkCompatibility with ERR_PNPM_UNEXPECTED_VIRTUAL_STORE, and — because a plain install runs with forceNewModules — prompts to purge node_modules.

The root workspace usually escapes this only because the optimistic "Already up to date" check short-circuits before validation (and a depless root manifest passes the deps-status check), so the mismatch surfaces in packages that actually have dependencies.

Which Node.js version are you using?

24.16.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)

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Fields

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions