Skip to content

Vendored pnpm 10.5+ with overrides: in pnpm-workspace.yaml: the new package.json pnpm.overrides shadows the user's overrides, so frozen installs fail and a re-lock drops them #360

Description

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

Summary

On pnpm 10.5 and later, overrides: can live in pnpm-workspace.yaml. When a project keeps its overrides there, vendor (and scan / get --mode vendored) adds the vendored file: override to that block. It also creates a brand-new pnpm.overrides object in package.json, a back-compat copy kept for pnpm 9/10 since #174. On pnpm 10, a pnpm.overrides field in package.json replaces the workspace-file overrides instead of merging with them. So the effective override set becomes {[email protected]: file:…} alone, while the rewritten lock records the user's overrides plus ours.

vendor reports success and vex attests not_affected, but:

  • every pnpm install --frozen-lockfile (CI, fresh clone, or the same checkout) fails with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH.
  • a plain pnpm install "fixes" this by re-locking without the user's overrides, which silently drops them. That can be a security pin, since overrides are commonly used for exactly that.

pnpm 11+ is unaffected, because it doesn't read the package.json pnpm field.

Repro (pnpm 10.34.5, Linux)

mkdir p && cd p
echo '{"name":"p","version":"0.0.0","private":true,"dependencies":{"left-pad":"1.3.0"}}' > package.json
printf "packages:\n  - '.'\noverrides:\n  is-number: 6.0.0\n" > pnpm-workspace.yaml
pnpm install                       # lock records overrides: {is-number: 6.0.0}
# stage a .socket/manifest.json + blobs for pkg:npm/[email protected] (hand-staged, as in tests/e2e_vendor_pnpm_build.rs)
socket-patch vendor --offline --json   # status: success, action: applied
cat package.json                   # NEW: "pnpm": {"overrides": {"[email protected]": "file:.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz"}}
cat pnpm-workspace.yaml            # overrides: is-number: 6.0.0 + [email protected]: file:…
# fresh checkout of the committable files, empty store:
pnpm install --frozen-lockfile --offline
#  ERR_PNPM_LOCKFILE_CONFIG_MISMATCH  Cannot proceed with the frozen installation. The current "overrides" configuration doesn't match the value found in the lockfile
socket-patch vex --offline --output v.json   # exit 0, not_affected
pnpm install --no-frozen-lockfile --offline
sed -n '/^overrides/,/^$/p' pnpm-lock.yaml
# overrides:
#   [email protected]: file:.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz      <- is-number: 6.0.0 is gone

Expected vs actual

  • Expected: docs/ecosystems.md (vendored npm row) and fix(vendor): write pnpm overrides to pnpm-workspace.yaml for pnpm >= 11 #174 promise that the vendored lock plus overrides install with a cold pnpm install --frozen-lockfile --offline from the committable files, and that user overrides are preserved (a conflicting one is refused with vendor_override_conflict, per CLI_CONTRACT.md).
  • Actual: vendoring succeeds, but the committable state can't be frozen-installed on pnpm 10.5+. The only remedy pnpm offers (a re-lock) deletes the user's overrides.

Matrix (Linux, current main f6b7fb9)

pnpm user overrides in pnpm-workspace.yaml vendor fresh --frozen-lockfile --offline
10.0.0 yes (pnpm 10.0 ignores them) success pass
10.5.2 yes success ERR_PNPM_LOCKFILE_CONFIG_MISMATCH
10.12.1 yes success ERR_PNPM_LOCKFILE_CONFIG_MISMATCH
10.34.5 yes success ERR_PNPM_LOCKFILE_CONFIG_MISMATCH (reproduced 3×)
11.27.0 yes success pass
12.8.1 yes success pass
10.34.5 no workspace overrides success pass

Released 4.0.0 behaves the same (not a v5 regression). This is config logic, not OS-specific.

Suspect code

crates/socket-patch-core/src/vendor/pnpm_lock.rs:1585 (apply_pkg_override) always creates pnpm.overrides in package.json. When pnpm-workspace.yaml already carries a top-level overrides: block (see ws_overrides_section, :1667, and apply_workspace_override, :1735), the package.json copy should be skipped, because on pnpm 10.5+ it shadows the workspace block. The alternative is to copy the user's workspace overrides into it, but that doubles the surface.

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

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions