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

  1. mikolalysenko commented on Oct 6, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Structural cause tracked in #905. workspace::top_level_key doesn't skip a BOM, while the other pnpm-workspace.yaml key reader (governing_root::workspace_lockfile_dir) does. This is one of about 50 hand-rolled BOM decisions. #905 adds one shared strip_bom and makes workspace_lockfile_dir a top_level_key caller.


    Generated by Claude Code

  2. mikolalysenko commented on Oct 6, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Shares root cause with #903, #905: the formats::pnpm lock and workspace readers (head_lock_version, lock_versions, is_pnpm_lock_text, workspace::top_level_key) match a column-0 literal and never skip a leading UTF-8 BOM. Will be fixed together.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 6, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (with #903, #905; shared root cause: pnpm lock/workspace readers don't skip a leading UTF-8 BOM). Branch: agent/fix-pnpm-bom-readers. Claim-ID: 2026-10-06T01:20:29Z-3fcf3e


    Generated by Claude Code

  4. mikolalysenko commented on Oct 6, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Fix in progress: #909


    Generated by Claude Code

  5. mikolalysenko commented on Oct 6, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Version data from pnpm bug-hunt run 25 (main 9c43dfc, Linux): vendored mode reproduces on pnpm 9.15.9 and 10.34.5 as well as 11 / 12. The repro is a BOM pnpm-workspace.yaml whose first key is overrides: (is-number: 7.0.0). scan --mode vendored exits 0 with success and appends a second top-level overrides: block for left-pad@1.3.0. The next pnpm install --frozen-lockfile fails on the duplicate key at line 6, so nothing is installed.

    Control: with the same BOM file but packages: as the first key (so overrides: is new), both versions pass and install the patched bytes. #909's tests may want a pnpm ≤10 vendored leg.


    Generated by Claude Code

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