Skip to content

Agent mode ignores pnpm's modulesDir: on pnpm 10.12+ every installed package is "not installed", and apply exits 0 leaving it unpatched #661

Description

[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).

Summary

pnpm's modulesDir setting (modules-dir in .npmrc, modulesDir: in pnpm-workspace.yaml) renames the project's node_modules. Since pnpm 10.12.0, the default virtual store follows it (<modulesDir>/.pnpm), so a project with modulesDir: deps has no node_modules at all. Every package lives in deps/.pnpm/<name>@<ver>/node_modules/<name>.

The npm crawler only collects directories literally named node_modules, plus the configured roots in configured_install_roots (yarn classic --modules-folder from #493, and Rush common/temp from #518). It never reads pnpm's modulesDir. So agent-mode apply / scan --apply sees nothing installed. Because pnpm-lock.yaml resolves the purl, it classifies the installed package as lockfile-only (package_not_installed, "resolved by the project lockfile"), which by contract never fails the run. Result: exit 0, status success, and the installed copy stays unpatched.

Release 4.0.0 failed loudly on the same fixture (exit 1, "no matching packages were found on disk"). The v5 lockfile-only classification turned this into a silent pass.

Impact

Repro (pnpm 12.8.1, Linux, main 045d7ec)

mkdir proj && cd proj
echo '{"name":"root","version":"1.0.0","dependencies":{"is-odd":"3.0.1","left-pad":"1.3.0"}}' > package.json
printf 'modulesDir: deps\n' > pnpm-workspace.yaml          # pnpm 10: echo modules-dir=deps > .npmrc
pnpm install
ls deps/.pnpm                                               # is-number@6.0.0 is-odd@3.0.1 left-pad@1.3.0 lock.yaml
# .socket/manifest.json + blobs: a patch for pkg:npm/left-pad@1.3.0 package/index.js (prepends a marker)
socket-patch apply --offline
#   Note: 1 manifest patch targets a package not installed on this host (resolved by the project lockfile; skipped):
#     - pkg:npm/left-pad@1.3.0
#   Summary: 0 of 1 targeted patch applied, 0 already patched, 1 not found on disk
echo $?                                                     # 0
head -c 30 deps/.pnpm/left-pad@1.3.0/node_modules/left-pad/index.js   # upstream bytes, no marker
NODE_PATH=deps node -e 'require("left-pad")'                # loads the unpatched copy
socket-patch vex --offline --json --output v.json           # exit 1, no_applicable_patches (honest)

It's the same in a workspace (packages: [packages/*] + modulesDir: deps, with a member depending on left-pad): 0 of 1 applied, exit 0.

Expected vs actual

Matrix (Linux, Node 22, main 045d7ec; each cell run 2×)

pnpm modulesDir honoured where virtual store agent apply
7.33.7 / 8.15.9 / 9.15.9 .npmrc modules-dir=deps node_modules/.pnpm (deps/ holds only links into it) pass (store copy patched)
10.0.0 / 10.5.2 / 10.7.1 / 10.9.0 / 10.10.0 / 10.11.1 .npmrc node_modules/.pnpm pass
10.12.0 / 10.12.1 / 10.20.0 / 10.28.0 / 10.34.5 .npmrc deps/.pnpm fail: package_not_installed, exit 0
11.28.3 / 12.8.1 pnpm-workspace.yaml deps/.pnpm fail: same

First pnpm version affected: 10.12.0 (the virtual store moved under modulesDir). socket-patch release 4.0.0 on pnpm 12.8.1: exit 1, loud "no matching packages were found on disk". Main is silent (exit 0). macOS and Windows weren't probed (the routine's probe branches are on hold), but the cause is platform-independent.

Suspect code

  • crates/socket-patch-core/src/crawlers/npm_crawler.rs:45 configured_install_roots handles .yarnrc --modules-folder and rush.json but not pnpm modulesDir (from pnpm-workspace.yaml on 10+ and .npmrc modules-dir on ≤10, plus pnpm's global config.yaml / rc).
  • The lockfile-only classification behind the package_not_installed detail ("resolved by the project lockfile") is what turns the miss into exit 0.

No duplicate found: #362 covers virtualStoreDir, #493 covers yarn classic --modules-folder (closed via #520, yarn only), and #373 / #495 / #359 cover other stores.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions