Skip to content

pnpm-workspace.yaml with a UTF-8 BOM: hosted and vendored miss the first top-level key and append a duplicate trustLockfile / overrides, so every pnpm install fails with "duplicate mapping key" after a successful scan #904

Description

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

Summary

formats::pnpm::workspace::top_level_key (the scanner #402 introduced so the workspace-file splices see every key spelling) doesn't strip a leading UTF-8 BOM. When pnpm-workspace.yaml starts with \xEF\xBB\xBF and its first top-level key is the one socket-patch edits, the key reads as \u{FEFF}trustLockfile (or \u{FEFF}overrides) and isn't recognised. pnpm's YAML parser strips the BOM and sees the real key, so it accepts the file as it stands.

  • Hosted (scan --mode hosted, 9.0 lock): the existing trustLockfile: is missed, and a second trustLockfile: true is appended. If the user wrote trustLockfile: false, that explicit choice is no longer respected, though CLI_CONTRACT says explicit user settings are preserved. Either way the file now has a duplicate key.
  • Vendored (scan --mode vendored, pnpm 10+ workspace overrides: mirror): the existing overrides: block is missed, and a second top-level overrides: with the file:.socket/vendor/… entry is appended.

Both runs report status: success, exit 0.

Impact

pnpm then refuses to parse the workspace file, so every pnpm command in the project fails, not just installs of the patched package:

  • pnpm 12.8.1: pnpm-workspace.yaml: error: line 4 column 1: duplicate mapping key: trustLockfile, set DuplicateKeyPolicy in Options if acceptable
  • pnpm 11.28.3: [ERROR] duplicated mapping key (4:1)

This is the failure class #402 fixed for quoted and key : spellings, reached through a BOM, for example from a Windows editor that saves "UTF-8 with signature". Unlike the vendored lock/package.json gates (vendor_lockfile_crlf_unsupported, vendor_pkg_json_unsupported for a BOM), nothing refuses the file.

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

# hosted
mkdir h && cd h
echo '{"name":"b","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > package.json
printf '\xef\xbb\xbftrustLockfile: false\npackages:\n  - .\n' > pnpm-workspace.yaml
pnpm install                                    # OK (pnpm 12.8.1)
socket-patch scan --mode hosted --yes --json    # status success, rewrittenFiles: [pnpm-lock.yaml, pnpm-workspace.yaml]
grep -c trustLockfile pnpm-workspace.yaml       # 2
rm -rf node_modules && pnpm install --frozen-lockfile   # duplicate mapping key: trustLockfile

# vendored
mkdir ../v && cd ../v
echo '{"name":"b","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > package.json
printf '\xef\xbb\xbfoverrides:\n  is-number: 7.0.0\npackages:\n  - .\n' > pnpm-workspace.yaml
pnpm install
socket-patch scan --mode vendored --yes --json  # status success
grep -c 'overrides:' pnpm-workspace.yaml        # 2
rm -rf node_modules && pnpm install --frozen-lockfile --offline   # duplicate mapping key: overrides

Expected vs actual

  • Expected: CLI_CONTRACT's pnpm trust-config paragraph says the write "preserves explicit user settings (an existing top-level key in any YAML spelling …)", and that "a file a line append would corrupt … is left untouched and the warning gives the manual recoveries". The vendored overrides: mirror "reads keys the same way". So either the BOM is stripped before the keys are matched (a BOM'd trustLockfile: true is then already configured, and false is respected), or the file is left untouched with the manual-recovery warning.
  • Actual: a duplicate key is appended, the scan reports success, and pnpm can't parse the file.

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

arm first key pnpm main 9c43dfc release 4.0.0
hosted trustLockfile: true 12.8.1 fail (duplicate) fail
hosted trustLockfile: false 12.8.1 fail (duplicate; explicit false overridden) not run
hosted trustLockfile: true 11.28.3 fail not run
vendored overrides: 12.8.1 fail (duplicate) fail
hosted BOM + packages: first (control) 12.8.1 pass (key appended once, install patched) —

Not a regression. The code path is OS-independent; no macOS/Windows probe.

Suspect code

Probe runs: none (Linux reproduction only).

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