Skip to content

Hosted pnpm scan skips the trustLockfile: true auto-config when pnpm-lock.yaml starts with a UTF-8 BOM, so pnpm 11/12 frozen installs fail with ERR_PNPM_TARBALL_URL_MISMATCH after a successful scan #903

Description

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

Summary

On a pnpm-lock.yaml whose first line carries a UTF-8 BOM (\xEF\xBB\xBFlockfileVersion: '9.0'), scan --mode hosted rewrites the lock correctly (the hosted tarball and sha512 land) and reports success. But it does not write trustLockfile: true to pnpm-workspace.yaml. The version sniff formats::pnpm::lock_versions matches line.strip_prefix("lockfileVersion:"), and the BOM makes the first line miss, so lock_version_major returns None. The hosted engine's root-lock gate (root_lock_v9) then treats the lock as "not trust-policy era" and falls back to the manual guidance, as it would under --no-trust-lockfile-config.

pnpm itself reads BOM locks without complaint: a frozen install of the unmodified BOM lock succeeds on 11.28.3 and 12.8.1. A BOM typically comes from a Windows editor saving the lock "UTF-8 with signature".

Impact

  • pnpm 11 / 12: the next pnpm install --frozen-lockfile (CI) fails with ERR_PNPM_TARBALL_URL_MISMATCH, after a scan that exited 0 with status: success. The only signal is the generic redirect_pnpm_trust_lockfile text that also covers the opt-out case. The tempting pnpm-suggested fix (re-lock) discards the patch.
  • Legacy side of the same sniff: a BOM-prefixed pnpm 8 ('6.0') lock is no longer recognised as legacy (all_locks_legacy is false), so the warning gives the pnpm ≥ 11 advice (pnpm install --trust-lockfile, an option pnpm 8 doesn't have) instead of the legacy "no trust step needed" text. The pnpm 8 install itself works.

Repro (Linux, main 9c43dfc, local mock of the patch API)

mkdir bom && cd bom
echo '{"name":"b","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > package.json
pnpm install                                   # pnpm 12.8.1
printf '\xef\xbb\xbf' | cat - pnpm-lock.yaml > x && mv x pnpm-lock.yaml
rm -rf node_modules && pnpm install --frozen-lockfile --store-dir "$(mktemp -d)"   # OK: pnpm accepts the BOM lock
socket-patch scan --mode hosted --yes --json   # status success, rewrittenFiles: ["pnpm-lock.yaml"] only
ls pnpm-workspace.yaml                         # absent (without the BOM it is created with trustLockfile: true)
rm -rf node_modules && pnpm install --frozen-lockfile --store-dir "$(mktemp -d)"
# Error: ERR_PNPM_TARBALL_URL_MISMATCH
printf 'trustLockfile: true\n' > pnpm-workspace.yaml
rm -rf node_modules && pnpm install --frozen-lockfile --store-dir "$(mktemp -d)"   # OK, patched bytes installed

Expected vs actual

  • Expected (CLI_CONTRACT, "pnpm trust-config" paragraph): "For a 9.0 root lock, the CLI ensures pnpm-workspace.yaml carries trustLockfile: true". The rewriter already accepts this lock as 9.0 and splices it, so the trust gate should read the same version. A BOM-prefixed legacy lock should get the legacy text.
  • Actual: the trust step is skipped silently (exit 0), and the frozen install fails on pnpm ≥ 11.

Matrix (each cell run twice in fresh projects; Linux only)

pnpm lock trust written frozen install after scan
12.8.1 9.0 + BOM no fail ERR_PNPM_TARBALL_URL_MISMATCH
11.28.3 9.0 + BOM no fail ERR_PNPM_TARBALL_URL_MISMATCH
12.8.1 9.0, no BOM (control) yes pass
8.15.9 6.0 + BOM n/a pass, but the warning gives pnpm 11 advice

Release 4.0.0 behaves the same (no trust write on a BOM lock), so this isn't a regression. The code path is OS-independent; a Windows core.autocrlf + BOM checkout is the likely real-world source, but I didn't run a Windows probe.

Suspect code

  • crates/socket-patch-core/src/formats/pnpm/mod.rs:281 (lock_versions): line.strip_prefix("lockfileVersion:") without stripping a leading \u{FEFF} from the first line. lock_version_major (:297) and may_need_store_flag (:305, the shrinkwrapVersion: check) share the sniff.
  • crates/socket-patch-core/src/hosted/engine.rs:1294 (root_lock_v9) and :1307 (all_locks_legacy) consume it.

Probe runs: none (Linux reproduction only).

No activity

Activity on this issue will appear here.

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