Repository navigation
Hosted yarn berry pin of a catalog: dependency keys resolutions by the resolved npm: range, so every yarn install --immutable fails YN0028 (regression from #465) #632
Description
Activity
- addedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentpm:yarn-berryYarn Berry (2+)Yarn Berry (2+)
on Oct 3, 2026 mikolalysenko commented
on Oct 3, 2026 CollaboratorAuthorMore actions[agent] More evidence from the same run (main
045d7ec, yarn 4.18.1, Linux): the vendored → hosted takeover of acatalog:dependency also falls into this.scan --mode vendoredon the catalog project writes"resolutions": {"left-pad": "file:./.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz"}, and a freshyarn install --immutable --check-cachegets the patched bytes. Vendored mode works.scan --mode hostedon that project reportssuccess,redirected: 1, and warnsredirect_takeover_reverted_vendored. It reverts the working vendored pin and writes theleft-pad@npm:^1.3.0selector.- The next
yarn install --immutablefails with YN0028.
So the takeover replaces a working patch with a broken one and reports success.
Generated by Claude Code
- added a commit that references this issue
on Oct 3, 2026 mikolalysenko commented
on Oct 3, 2026 CollaboratorAuthorMore actions[agent] Triaged as
priority:p1(Yarn Berry). This is a regression from #465. Not a duplicate, and no open PR covers it.
Generated by Claude Code
mikolalysenko commented
on Oct 4, 2026 CollaboratorAuthorMore actions[agent] Claiming this issue (shared root cause: the hosted yarn berry
resolutionspin is keyed by the lock's expandednpm:range, but yarn matches resolutions against the manifest descriptor, which iscatalog:/catalog:<name>for catalog dependencies). Branch: agent/fix-yarn-berry-catalog-resolutions. Claim-ID: 2026-10-04T07:21:11Z-1b6a31
Generated by Claude Code
mikolalysenko commented
on Oct 4, 2026 CollaboratorAuthorMore actions- added a commit that references this issue
on Oct 4, 2026 mikolalysenko commented
on Oct 4, 2026 CollaboratorAuthorMore actions[agent] Verification of draft PR #763 (head
55dc0cb) from the Yarn Berry bug-hunt routine (ledger #305). Yarn 4.18.1, node-modules linker, Linux, with a local patch-API mock (plus/upstream/npm/<uuid>.jsonand a registry passthrough for rollback).catalog shape hosted pin fresh --immutablehardened fresh re-scan rollbackroot catalog:left-pad@npm:^1.3.0+left-pad@catalog:patched patched no-op (0 files) byte-exact root catalog:legacyleft-pad@npm:1.3.0+left-pad@catalog:legacypatched patched no-op byte-exact two workspaces, catalog:+catalog:legacy(merged lock entry)4 selectors patched patched no-op byte-exact workspace catalog:+ workspace^1.3.02 selectors patched patched no-op byte-exact devDependencies+peerDependenciescatalog:2 selectors patched patched no-op byte-exact vendored → hosted takeover ( catalog:andcatalog:legacy)redirect_takeover_reverted_vendored, then pinnedpatched patched — — On main
045d7ec, the same rootcatalog:project still fails YN0028 on a fresh--immutable. So, from the Berry side, #763 fixes every catalog shape tried here.
Generated by Claude Code
[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
Since #465 (
203e092), a hosted Berry pin is a rootpackage.jsonresolutionsentry keyed by the locked descriptor (left-pad@npm:^1.3.0), plus the lock entry re-keyedleft-pad@<url>. When the dependency is declared through a Yarn catalog ("left-pad": "catalog:", withcatalog: {left-pad: ^1.3.0}in.yarnrc.yml), yarn appliesresolutionsto the manifest descriptorleft-pad@catalog:before the catalog is expanded tonpm:^1.3.0. So theleft-pad@npm:^1.3.0selector never matches. Yarn resolves the registry release again, and the lock socket-patch wrote no longer matches what yarn computes.scan --mode hostedexits 0 withstatus: success,redirected: 1, and no warning. Then:yarn install --immutable(in place or in a fresh checkout) fails with YN0028 ("The lockfile would have been modified"). Yarn wants to turnleft-pad@<url>back intoleft-pad@npm:1.3.0.yarn installsilently installs the unpatched registry bytes and drops the pin fromyarn.lock. The staleresolutionsentry stays inpackage.json.scan --mode hostedreportsredirected: 1again and writes the same broken pin, so the loop never converges.Release 4.0.0, with its
::__archiveUrl=lock-only pin, handles the same project correctly: the fresh--immutableinstall gets the patched bytes. This is a regression.vexdoes the right thing after the mutable install. The lock no longer carries a pin, so it attests nothing (manifest_not_found). There's no false attestation.Impact
enableImmutableInstallsis on by default under CI) goes red immediately after the hosted commit.yarn installsilently get unpatched code. The command reports success throughout.Repro (Linux, yarn 4.18.1, node-modules linker)
The patch API was a local mock serving a granted
yarn-berry-zipartifact whoseyarnBerry10c0was bootstrapped with a real yarnresolutions: file:install, the same approach ascrates/socket-patch-cli/tests/e2e_redirect_yarn_berry_build.rs.Which selector yarn honours for a catalog dependency (mutable install with each hand-written
resolutionskey → URL):resolutionskeyleft-pad@npm:^1.3.0(what socket-patch writes)left-pad@npm:^1.3.0left-pad@catalog:left-pad@<url>left-pad(bare)left-pad@<url>A workspace mixing
catalog:(root and member b) with a namedcatalog:legacy(member a,1.3.0) fails the same way. socket-patch writesleft-pad@npm:1.3.0andleft-pad@npm:^1.3.0, and yarn wants a merged"left-pad@npm:1.3.0, left-pad@npm:^1.3.0"registry entry.Expected vs actual
docs/ecosystems.md(yarn berry hosted notes) says the redirect "pins the way yarn does for a rootresolutionsentry …package.jsonroutes the locked descriptor to the hosted tarball", andCLI_CONTRACT.mdsays a dep counts as redirected only when the pin actually lands. The pin should be keyed by the descriptor yarn matches resolutions against (name@catalog:/name@catalog:<named>for catalog deps). Failing that, a catalog-consumed descriptor should be refused loudly, the way pnpm vendoring refuses catalog-consumed deps (fix(vendor): refuse catalog-consumed deps in pnpm vendoring #184), rather than reported as success.redirected: 1, no warning. The next immutable install fails YN0028, and a mutable install is silently unpatched.Matrix
045d7ec(3 runs: minimal root, workspace + named catalog, re-scan loop)045d7ec--immutablepatched;::__archiveUrl=pin)First bad commit:
203e092(#465, "Fix yarn berry hosted pin leaking npm auth (#404)"), which introduced theresolutionspin. Run 8 of this routine passed the samecatalog:cell with the old__archiveUrlpin.Vendored mode isn't affected: it passed
catalog:andcatalog:legacyin run 8 because it pins by package name.Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:4081, inberry_resolutions_pin: selectors are built asformat!("{name}@{r}")from the lock entry's npm ranges (key_ranges). For a catalog-consumed dependency the manifest descriptor iscatalog:/catalog:<name>, which is what yarn's resolutions matcher sees.cataloghandling exists anywhere inpatch/redirect/mod.rs, so the hosted gate has no catalog refusal either.