You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Yarn berry hosted pin can't cover a descriptor added after pinning: re-scan refuses with an impossible "dedupe" remedy, and rollback reports success but leaves a lock every yarn install --immutable rejects (YN0028) #1082
[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
A hosted berry pin is a root resolutions selector for each descriptor that existed when you ran the scan (for example "lpx@npm:^1.0.0": "<socket url>"). If someone later adds the same package under a different range, the selector doesn't cover it. That happens when a workspace member adds "lpx": "1.0.0", or when a new dependency depends on lpx@~1.0.0. Yarn then locks a second, separate registry entry "lpx@npm:1.0.0" beside the Socket URL entry, and installs that copy unpatched. Three things go wrong after that:
A re-scan can't fix it.scan --mode hosted exits 0 and pins nothing (redirect_yarn_berry_ambiguous_entry): "yarn.lock holds 2 separate entries resolving lpx@1.0.0; run yarn install once to dedupe the lock, then re-run". Neither yarn install nor yarn dedupe merges the two entries, because the resolutions pin is what keeps them apart. The suggested fix can't work, and nothing else is offered.
Rollback breaks the lock.rollback (and remove) exit 0 with "Restored pkg:npm/lpx@1.0.0", but they write back two blocks with the same resolution ("lpx@npm:1.0.0" and "lpx@npm:^1.0.0", both resolution: "lpx@npm:1.0.0"). Yarn merges those into "lpx@npm:1.0.0, lpx@npm:^1.0.0", so every fresh yarn install --immutable fails with YN0028.
This is a normal workflow: someone adds a dependency after the hosted pin. Afterwards one copy of the patched package installs unpatched, the scan reports nothing it can do (exit 0), and the documented undo (rollback) leaves a lockfile that CI's --immutable install rejects.
mkdir -p proj/packages/b &&cd proj
echo'{"name":"root","version":"1.0.0","private":true,"workspaces":["packages/*"],"dependencies":{"lpx":"^1.0.0"}}'> package.json
printf'nodeLinker: node-modules\n'> .yarnrc.yml
yarn install
socket-patch scan --mode hosted --yes # pins lpx@npm:^1.0.0 → socket url (resolutions + lock)echo'{"name":"b","version":"1.0.0","dependencies":{"lpx":"1.0.0"}}'> packages/b/package.json
yarn install # adds a separate "lpx@npm:1.0.0" registry entry
head -1 packages/b/node_modules/lpx/index.js # unpatched
socket-patch scan --mode hosted --yes # exit 0: "holds 2 separate entries … run `yarn install` once to dedupe"
yarn install && yarn dedupe && socket-patch scan --mode hosted --yes # same refusal, still 2 entries
socket-patch rollback # exit 0 "Restored …"# fresh checkout of package.json/yarn.lock/.yarnrc.yml:
yarn install --immutable # YN0028 (lock would merge the two entries)
Expected vs actual
Expected: a re-scan pins the new descriptor too. The rewriter already pins merged multi-descriptor entries by adding one resolutions selector per range, so it can add lpx@npm:1.0.0 and fold the registry entry into the URL entry. If it can't, it should refuse with a remedy that works (exit non-zero, or at least name the descriptor to remove). CLI_CONTRACT.md / docs/ecosystems.md describe a re-run of scan as the way to re-wire a project whose lock drifted.
Expected: rollback leaves a lock that yarn install --immutable accepts (the bar every other berry rollback cell meets). If it can't produce one, it should fail loudly rather than report success.
Tested on main 05ecc6e, and on PR #1033 head 314038b for the re-scan and VEX columns. Not bisected. Releases ≤4.0.0 pinned through an ::__archiveUrl= locator instead of resolutions.
Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:4141-4152: targets.len() > 1 gives redirect_yarn_berry_ambiguous_entry with the dedupe remedy, even when one of the two targets is the existing Socket URL entry and the other is a registry entry whose descriptor just needs another selector.
crates/socket-patch-core/src/patch/redirect/upstream/npm.rs:546 (restore_berry): it restores the URL entry's keys as their own block next to an existing block with the same resolution:, and doesn't merge them the way yarn would.
Priority: P1 → P2. Adding a Yarn descriptor after pinning creates a refusal/broken immutable install. Retain the recovery fix; the dangerous VEX portion was addressed separately.
[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
A hosted berry pin is a root
resolutionsselector for each descriptor that existed when you ran the scan (for example"lpx@npm:^1.0.0": "<socket url>"). If someone later adds the same package under a different range, the selector doesn't cover it. That happens when a workspace member adds"lpx": "1.0.0", or when a new dependency depends onlpx@~1.0.0. Yarn then locks a second, separate registry entry"lpx@npm:1.0.0"beside the Socket URL entry, and installs that copy unpatched. Three things go wrong after that:scan --mode hostedexits 0 and pins nothing (redirect_yarn_berry_ambiguous_entry): "yarn.lock holds 2 separate entries resolving lpx@1.0.0; runyarn installonce to dedupe the lock, then re-run". Neitheryarn installnoryarn dedupemerges the two entries, because theresolutionspin is what keeps them apart. The suggested fix can't work, and nothing else is offered.rollback(andremove) exit 0 with "Restored pkg:npm/lpx@1.0.0", but they write back two blocks with the same resolution ("lpx@npm:1.0.0"and"lpx@npm:^1.0.0", bothresolution: "lpx@npm:1.0.0"). Yarn merges those into"lpx@npm:1.0.0, lpx@npm:^1.0.0", so every freshyarn install --immutablefails with YN0028.vexon main attestsnot_affectedwhilepackages/b/node_modules/lpxis unpatched. Open PR Stop VEX attesting over yarn PnP, pnpm bundled and deno.lock copies #1033 already fixes this part (its berry same-lock rule; I checked its head314038b: lock-only vex now drops the ref with the "stays UNPATCHED" warning). But Stop VEX attesting over yarn PnP, pnpm bundled and deno.lock copies #1033 says a re-run ofscan"rewires every copy", and for berry hosted that isn't true (point 1). With Stop VEX attesting over yarn PnP, pnpm bundled and deno.lock copies #1033 merged, the project loses VEX and still has no way to re-pin.Impact
This is a normal workflow: someone adds a dependency after the hosted pin. Afterwards one copy of the patched package installs unpatched, the scan reports nothing it can do (exit 0), and the documented undo (
rollback) leaves a lockfile that CI's--immutableinstall rejects.Repro (local registry + mock patch API; synthetic
lpx@1.0.0)Expected vs actual
resolutionsselector per range, so it can addlpx@npm:1.0.0and fold the registry entry into the URL entry. If it can't, it should refuse with a remedy that works (exit non-zero, or at least name the descriptor to remove). CLI_CONTRACT.md / docs/ecosystems.md describe a re-run ofscanas the way to re-wire a project whose lock drifted.rollbackleaves a lock thatyarn install --immutableaccepts (the bar every other berry rollback cell meets). If it can't produce one, it should fail loudly rather than report success.OS × version
Tested on main
05ecc6e, and on PR #1033 head314038bfor the re-scan and VEX columns. Not bisected. Releases ≤4.0.0 pinned through an::__archiveUrl=locator instead ofresolutions.Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:4141-4152:targets.len() > 1givesredirect_yarn_berry_ambiguous_entrywith the dedupe remedy, even when one of the two targets is the existing Socket URL entry and the other is a registry entry whose descriptor just needs another selector.crates/socket-patch-core/src/patch/redirect/upstream/npm.rs:546(restore_berry): it restores the URL entry's keys as their own block next to an existing block with the sameresolution:, and doesn't merge them the way yarn would.crates/socket-patch-core/src/vex/discover/yarn.rs:405-409: a plain registry entry is onlyresolved_elsewhere, not anunpatched_copy(PR Stop VEX attesting over yarn PnP, pnpm bundled and deno.lock copies #1033 changes this).Backlog review — 2026-10-08
Priority: P1 → P2. Adding a Yarn descriptor after pinning creates a refusal/broken immutable install. Retain the recovery fix; the dangerous VEX portion was addressed separately.