Repository navigation
Hosted and vendored modes create a packages: ['.'] pnpm-workspace.yaml that turns a single-package project into a workspace, so pnpm add <pkg> fails with ERR_PNPM_ADDING_TO_ROOT on pnpm 9.0–10.4 #734
Description
[agent] Found by the scheduled pnpm bug-hunt routine (ledger #303).
Summary
For any project with a lockfileVersion 9.0 pnpm-lock.yaml and no pnpm-workspace.yaml, scan --mode hosted creates the scaffold
packages:
- '.'
trustLockfile: trueand scan --mode vendored creates the same packages: ['.'] scaffold with an overrides: block. On pnpm 9.0.0 through 10.4.1, that file makes pnpm treat the plain single-package project as a workspace whose only member is the root. The most common day-to-day command, pnpm add <pkg>, then fails:
ERR_PNPM_ADDING_TO_ROOT Running this command will add the dependency to the workspace root, which might not be what you want - if you really meant it, make it explicit by running this command again with the -w flag (or --workspace-root). ...
Nothing is added to package.json or the lock. Before the scan, the same pnpm add works.
The packages: key can't just be dropped. pnpm 9 refuses a workspace file without it (ERROR packages field missing or empty, checked below), and the code comment at guidance.rs says the scaffold exists for that reason. On these versions the hosted half is also unnecessary: the docs say pnpm <= 10 doesn't need trustLockfile ("pnpm >=11 needs this for hosted URLs … pnpm <=10 does not need the setting", docs/ecosystems.md). So hosted mode changes the project's pnpm semantics for a setting those pnpm versions don't use.
Impact
- Every developer and CI job on pnpm 9.x (and 10.0–10.4) that later runs
pnpm add <pkg>in a project socket-patch touched gets a hard error. The error message talks about workspaces, not socket-patch, so the link to the scan isn't obvious. - This affects hosted mode, which is the v5 default for a bare
scan, and vendored mode. - The workaround is
pnpm add -w <pkg>orignore-workspace-root-check=true. With-wthe hosted pin survives, which I checked on 9.15.9.
Repro (Linux, Node 22)
mkdir app && cd app
printf '{"name":"app","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}\n' > package.json
npx pnpm@9.15.9 install
npx pnpm@9.15.9 add is-number@7.0.0 # control: works (then revert, or use a fresh dir)
# fresh dir, same package.json + install, then:
socket-patch scan --mode hosted --yes # (or --mode vendored)
cat pnpm-workspace.yaml # packages: ['.'] + trustLockfile: true
npx pnpm@9.15.9 add is-number@7.0.0 # ERR_PNPM_ADDING_TO_ROOT, exit 1, nothing added(I used a local mock of the patch API serving a real patched left-pad@1.3.0 tarball. Any granted pnpm 9.0 lock pin reproduces it.)
Control showing why packages: is needed on pnpm 9:
printf 'trustLockfile: true\n' > pnpm-workspace.yaml
npx pnpm@9.15.9 add is-number@7.0.0 # ERROR packages field missing or empty
npx pnpm@9.15.9 install --frozen-lockfile # ERROR packages field missing or emptyExpected vs actual
- Expected: CLI_CONTRACT says the hosted write "preserves user bytes" and that installs "need no extra flags". It describes the scaffold only as a vehicle for
trustLockfile, which pnpm >= 11 requires. Ensuring trust (or vendored overrides) shouldn't change how the user's own pnpm commands behave, and on pnpm <= 10 hosted mode doesn't need the file at all. - Actual: after a successful scan,
pnpm add <pkg>exits 1 withERR_PNPM_ADDING_TO_ROOTon pnpm 9.0.0 – 10.4.1.
Matrix (Linux, socket-patch main 045d7ec; pnpm add is-number@7.0.0 after the scan)
| pnpm | hosted | vendored | control (no scan) |
|---|---|---|---|
| 9.0.0 | fail ADDING_TO_ROOT | untested | pass |
| 9.7.1 | fail | untested | pass |
| 9.15.9 | fail (3×) | fail | pass |
| 10.0.0 | fail (2×) | fail | pass |
| 10.1.0 / 10.2.1 / 10.3.0 / 10.4.1 | fail | untested | pass |
| 10.5.0 / 10.5.2 / 10.12.1 / 10.34.5 | pass | pass (10.5.0) | pass |
| 11.0.0 / 11.28.3 / 12.8.1 | pass (see note) | untested | pass |
| 7.33.7 / 8.15.9 | n/a (legacy locks get no scaffold) | n/a | pass |
pnpm 10.5.0 is the first pnpm release that no longer refuses in a root-only workspace.
Note, not part of this bug: on pnpm 11.0.0 / 11.28.3, pnpm add <other> succeeds but re-resolves the hosted pin back to upstream. pnpm 9, 10 and 12 keep it. That's the same pnpm 11 re-resolution recorded in #713.
Not a regression: release 4.0.0 writes the same scaffold and fails the same way on pnpm 9.15.9. 3.3.0 has no hosted mode.
Suspect code
crates/socket-patch-core/src/hosted/guidance.rs:252:TrustPlan::Create("packages:\n - '.'\ntrustLockfile: true\n")runs for every 9.0 root lock, whatever pnpm version the project uses.crates/socket-patch-core/src/vendor/pnpm_lock.rs:95:WS_SCAFFOLD_PACKAGES, the same root-only scaffold on the vendored side.
Possible directions (for maintainers): skip creating the hosted scaffold when the project pins pnpm <= 10 (packageManager, engines, devEngines), since pnpm <= 10 doesn't need the key; or also write ignore-workspace-root-check=true (.npmrc) / ignoreWorkspaceRootCheck: true when socket-patch creates the scaffold; or at least document the -w requirement in the redirect_pnpm_trust_lockfile detail and in pnpm-compatibility.md.
No probe runs: this is Linux-only evidence. The behaviour comes from pnpm's own workspace detection, so I don't expect it to depend on the OS.
Backlog review — 2026-10-08
Priority: P1 → P2. The generated workspace scaffold makes pnpm 9.0-10.4 reject later pnpm add commands. pnpm add -w or the workspace-root-check setting provides a workaround; keep the compatibility fix.
Activity
pnpm: 2026-10-04 run 15 ledger (filed #734)
mikolalysenko commentedon Oct 4, 2026
[agent] Triaged:
priority:p1(pnpm). Not a duplicate; no existing fix PR. Both scaffold writers are the cited sites (hosted/guidance.rsTrustPlan::Createandvendor/pnpm_lock.rsWS_SCAFFOLD_PACKAGES). The fix needs a choice between the listed directions (version-gated scaffold vs. also writingignoreWorkspaceRootCheck), so the PR should state which one it takes and why.Generated by Claude Code
pnpm: run 22 ledger (#880, #881 filed; #362/#590 verified; #435/#734 …
mikolalysenko commentedon Oct 7, 2026
[agent] Claiming this issue as part of the pnpm open-issue sweep in draft PR #1007. Branch: agent/fix-pnpm-open-issues. Claim-ID: 2026-10-07T12:44:29Z-pnpm07
Skip the root-only pnpm-workspace.yaml on pnpm 9.0-10.4 (#734)
Merge branch 'pnpm-fix/b3-lockselect' into agent/fix-pnpm-open-issues
Address review findings on the pnpm open-issues branch
Pin the pnpm bench fixture to pnpm 11 (#734)
Warn when the pnpm tarball restore guesses; name the pin in the scaff…
Fix the pnpm tarball-guess warning's remedy, scope and Rush handling (#…
mikolalysenko commentedon Oct 7, 2026
[agent] PR #1007 fixes this issue. It has a regression test that fails on
main, CI is fully green (552 checks) and it's ready for review. The issue will close when #1007 merges. The PR description's table gives the root cause, the fix and the test for each issue.Merge origin/main (#1008) into agent/fix-pnpm-open-issues
Scaffold packages in keyless pnpm-workspace.yaml