Repository navigation
Hosted yarn berry rollback/remove rebuilds the lock entry as a bare name@npm:<version> locator and drops the registry's ::__archiveUrl= binding, so projects on registries with non-conventional tarball URLs can't install after a revert #817
Description
[agent] Found by the scheduled Yarn Berry (2+) bug-hunt routine (ledger #305).
Summary
When a project's registry (npmRegistryServer) returns dist.tarball URLs that aren't at yarn's conventional path (<registry>/<name>/-/<name>-<version>.tgz), yarn locks the package as resolution: "left-pad@npm:1.3.0::__archiveUrl=<percent-encoded tarball URL>", and fetches from that URL.
scan --mode hosted pins such an entry correctly. But rollback and remove rebuild the original entry in restore_berry as a bare resolution: "left-pad@npm:1.3.0" and drop the ::__archiveUrl= binding. Yarn trusts the locked locator, so a cold-cache yarn install --immutable then fetches <registry>/left-pad/-/left-pad-1.3.0.tgz. On a registry that only serves the URLs it advertises, that fails with YN0001. The lock from before the hosted pin installs fine against the same registry.
Release 4.0.0 kept the original entry verbatim in .socket/vendor/redirect-state.json ("original": "...::__archiveUrl=http%3A%2F%2F127.0.0.1%3A8766%2Ffiles%2F..."), so its revert was exact. v5 dropped the hosted ledger and rebuilds the entry from registry metadata (SOCKET_NPM_REGISTRY, npmjs by default), which never sees the project's registry or its tarball URL.
Impact
- After
socket-patch rollbackorremove, the restoredyarn.lockdiffers from what yarn wrote: the locator loses the binding. - On registries whose advertised tarball URLs differ from the conventional path and which don't also serve the conventional path, every fresh or CI install (cold cache) fails after the revert. Proxies that point
dist.tarballat another host or path are one example; GitHub Packages-style/download/@scope/name/<v>/<hash>URLs are another. Warm caches hide it, because yarn finds the zip by checksum. yarn install --immutabledoes not flag the lock change (hardened mode and--refresh-lockfileaccept it too), so the broken lock is committed silently.
This is the yarn-berry counterpart of #557 (pnpm rollback drops tarball:).
Repro
The repro uses a local registry proxy that rewrites every dist.tarball to http://127.0.0.1:8766/files/<url-encoded npmjs tarball URL> and serves only those URLs. It also uses a mock patch API serving batch, by-package, view, patches/package (with the yarn-berry-zip yarnBerry10c0), the hosted tarball and /upstream/npm/<uuid>.json.
mkdir hD && cd hD
echo '{"name":"hD","private":true,"dependencies":{"left-pad":"^1.3.0"}}' > package.json
printf 'nodeLinker: node-modules\nenableGlobalCache: false\nnpmRegistryServer: "http://127.0.0.1:8766"\nunsafeHttpWhitelist: ["127.0.0.1"]\n' > .yarnrc.yml
yarn install # lock: resolution "left-pad@npm:1.3.0::__archiveUrl=http%3A%2F%2F127.0.0.1%3A8766%2Ffiles%2F..."
cp yarn.lock /tmp/lock.orig
SOCKET_NPM_REGISTRY=http://127.0.0.1:8766 socket-patch scan --mode hosted --json --yes \
--api-url $MOCK --api-token x --org org --patch-server-url $MOCK # success, redirected: 1
# (fresh checkout + yarn install --immutable here: patched, exit 0)
SOCKET_NPM_REGISTRY=http://127.0.0.1:8766 socket-patch rollback --json \
--api-url $MOCK --api-token x --org org --patch-server-url $MOCK # success, reverted: [pkg:npm/left-pad@1.3.0]
git diff --no-index /tmp/lock.orig yarn.lock
# - resolution: "left-pad@npm:1.3.0::__archiveUrl=http%3A%2F%2F127.0.0.1%3A8766%2Ffiles%2Fhttps%253A%252F%252Fregistry.npmjs.org%252Fleft-pad%252F-%252Fleft-pad-1.3.0.tgz"
# + resolution: "left-pad@npm:1.3.0"
# fresh checkout, cold cache:
YARN_GLOBAL_FOLDER=$(mktemp -d) yarn install --immutable
# ➤ YN0001: │ RequestError: socket hang up (GET /left-pad/-/left-pad-1.3.0.tgz, which the registry doesn't serve)
# exit 1With /tmp/lock.orig restored, the same cold-cache yarn install --immutable exits 0. remove pkg:npm/left-pad@1.3.0 behaves the same as rollback. Vendored vendor --revert on the same project is byte-exact and installs fine.
Expected vs actual
- Expected: per docs/testing/yarn-berry-compatibility.md,
rollback/removerestore the "upstream entries", meaning the entry yarn resolves from the project's registry. The project must be installable afterwards, as it was before the pin (release 4.0.0 restored the entry byte-exact). At minimum, when the pinned entry's original locator can't be rebuilt, the revert should refuse loudly, as it already does for other unrebuildable entries ("restore it from version control"). - Actual: exit 0,
reverted, and a lock whose locator yarn fetches from a URL the registry never advertised.
Matrix (Linux; main 045d7ec)
| yarn | rollback | remove | control (original lock, cold cache) |
|---|---|---|---|
| 4.0.2 | fail (YN0001) | fail (YN0001) | pass |
| 4.12.0 | fail (YN0001) | fail (YN0001) | pass |
| 4.18.1 | fail (YN0001) | fail (YN0001) | pass |
Each cell was run twice. A control project on the default registry (conventional URLs) rolls back byte-exact. Release 4.0.0 recorded the original entry in redirect-state.json, so this behaviour dates from the v5 removal of the hosted ledger. I didn't bisect the exact commit. macOS and Windows weren't probed (the restore is platform-independent string surgery).
Suspect code
crates/socket-patch-core/src/patch/redirect/upstream/npm.rs:557:restore_berrywritesresolution: "{name}@npm:{version}"unconditionally. The project's.yarnrc.ymlnpmRegistryServer/npmScopesand the registry'sdist.tarballare never consulted, andnpm_dist(client.rs:280) readsSOCKET_NPM_REGISTRYrather than the project's registry.
Activity
mikolalysenko commentedon Oct 5, 2026
[agent] Triaged:
priority:p1(yarn berry). Not a duplicate. Confirmed on main045d7ec:restore_berry(crates/socket-patch-core/src/patch/redirect/upstream/npm.rs) matches the pin, then rebuilds the entry as a barename@npm:<version>locator. Nothing re-derives the::__archiveUrl=binding that yarn adds when the registry'sdist.tarballis not at the conventional path. The pnpm counterpart is #557, but that bug is in different code (formats/pnpm/grammar.rsResolution::restore), so the two are not clustered. No open PR addresses this.Generated by Claude Code
mikolalysenko commentedon Oct 5, 2026
[agent] Claiming this issue (with #557). Shared root cause: the hosted npm-family restorers for pnpm and yarn berry discard the registry's
dist.tarballin cases where the package manager would record it (pnpmtarball:, berry::__archiveUrl=). Branch: agent/fix-npm-restore-registry-tarball. Claim-ID: 2026-10-05T01:21:10Z-efea98Generated by Claude Code
mikolalysenko commentedon Oct 5, 2026
[agent] Draft PR: #818
Generated by Claude Code
Add failing tests for tarball-dropping restores
Keep registry tarball URLs on hosted restore
mikolalysenko commentedon Oct 5, 2026
[agent] Yarn Berry (2+) bug-hunt routine (ledger #305): I found another way to hit this: the hosted→vendored takeover. Nothing errors at takeover time, but the broken entry ends up stored in the vendored ledger.
Setup: a custom registry (
npmRegistryServer) whosedist.tarballURLs are non-conventional, so yarn locksleft-pad@npm:1.3.0::__archiveUrl=…. The conventional/<name>/-/<name>-<v>.tgzpath returns 404, as on Artifactory-style mirrors.scan --mode hostedpins left-pad (fresh immutable install passes).vendor(orscan --mode vendored) takes over. The run succeeds and the vendored state installs fine.vendor --revert→yarn.locknow hasresolution: "left-pad@npm:1.3.0". The::__archiveUrl=binding is gone, andpackage.jsonis byte-exact.YARN_GLOBAL_FOLDER,yarn install --immutablefails withYN0035: left-pad@npm:1.3.0: Package not found (404).Cause: the takeover reverts the hosted pin through
restore_berry(upstream/npm.rs:559) before vendoring. That revert writes the bare locator, and the vendored ledger then records it as the pre-vendor entry:.socket/vendor/state.jsonstores"left-pad@npm:1.3.0"as the original. So any latervendor --revertreproduces #817, even though a plain vendored revert keeps the binding (run 18: byte-exact).Matrix (Linux, main
045d7ec, each cell run twice): yarn 4.18.1 viavendorfails, 4.18.1 viascan --mode vendoredfails, 4.0.2 viavendorfails. Fixingrestore_berryto keep the original binding (release 4.0.0 kept it inredirect-state.json) should cover this path too.Generated by Claude Code
yarn-berry: run 19 ledger (#831, #817 comments)
Fix hosted restore dropping registry tarball URLs (#557, #817) (#818)