Repository navigation
After Bun migrates a vendored bun.lockb to bun.lock (bun install --save-text-lockfile), vendor --revert and rollback fail, and a superseding re-vendor drops the pre-vendor original so revert exits 0 with the project still vendored #784
Description
[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).
Summary
Vendored mode records bun.lockb wiring (kind: bun_lockb_package, file: bun.lockb) in .socket/vendor/state.json. Bun's documented binary → text migration, bun install --save-text-lockfile, deletes bun.lockb and writes bun.lock. The vendored tuples carry over ("pk-a": ["pk-a@.socket/vendor/npm/<uuid>/pk-a-1.0.0.tgz", {}, "sha512-…"]), but socket-patch still treats the entry as a bun.lockb entry. Every unwind path then breaks:
- Right after the migration:
vendor --revertandrollbackexit 1 withrevert_failed: "bun.lockb is missing; cannot safely revert the binary lock".scan --mode hosted(the takeover) exits 0 withredirected: 0,redirect_vendored_revert_failed, and the remedy "runsocket-patch vendor --revertto clean up". That remedy is the command that just failed.repairand a vendored re-run reportsuccessand change nothing. The only way out isgit checkout bun.lockb, which undoes the migration. - After a superseding patch (new uuid) is vendored on the migrated lock: the re-vendor rewrites
bun.lock(exit 0). Because the previous wiring was abun.lockbrecord,carry_forward_wiringcan't match it, so the newbun.lockrecord hasoriginal: nulland the registry original is lost.vendor --revertthen exits 0 withstatus: success,vendor_lock_entry_drifted("has no recorded pre-vendor original; left as-is (runbun installto re-resolve it from the registry)"),vendor_artifact_keptandvendor_revert_kept. The lock still pins the vendored tarball, and the advisedbun installkeeps it, because the lock entry satisfiespackage.json. The project stays patched with no supported way back.
Hosted mode is fine: a hosted bun.lockb migrated to bun.lock rolls back correctly, because hosted rollback re-derives the record from the registry.
Impact
- A team that vendored on
bun.lockband then followed Bun's own advice to move to the text lock (Bun ≥ 1.2) can no longer revert, roll back or switch to hosted. - Case 1 fails loudly (exit 1), except for the hosted takeover, which exits 0 having done nothing.
- Case 2 is silent:
vendor --revertreports success (exit 0) while the patched artifact stays wired into the lock and installed. The pre-vendor registry tuple is permanently gone from the state.
Repro
Uses a local mock of the patch API and npm registry: the same routes as e2e_redirect_bun_build.rs (patches/batch, by-package, view, package grant, hosted tarball), with the registry on a different origin from SOCKET_PATCH_SERVER_URL. Any vendored-capable patch reproduces it.
# bunfig.toml points [install] registry at the mock registry
echo '{"name":"app","version":"0.0.0","dependencies":{"pk-a":"1.0.0","pk-d":"1.0.0"}}' > package.json
bun-1.1.45 install # writes bun.lockb (or Bun ≥1.2 with saveTextLockfile = false)
git add -A && git commit -qm init
socket-patch scan --mode vendored --json --yes # exit 0, bun.lockb wired
rm -rf node_modules && bun-1.4.2 install --save-text-lockfile # bun.lockb deleted, bun.lock written with .socket/vendor tuples
# Case 1
socket-patch vendor --revert --json # exit 1, revert_failed: "bun.lockb is missing; cannot safely revert the binary lock"
socket-patch rollback --json --yes # exit 1, same
socket-patch scan --mode hosted --json --yes # exit 0, redirected 0, redirect_vendored_revert_failed → "run `socket-patch vendor --revert`"
# Case 2 (instead of the above): the API now serves a superseding patch (new uuid)
socket-patch scan --mode vendored --json --yes # exit 0, bun.lock re-pinned to the new uuid; state.json wiring: file bun.lock, original: null
socket-patch vendor --revert --json # exit 0 "success": vendor_lock_entry_drifted + vendor_artifact_kept + vendor_revert_kept
rm -rf node_modules && bun install # node_modules/pk-a is still the PATCHED bytes; bun.lock still pins .socket/vendor/…Expected vs actual
- Expected:
docs/testing/bun-compatibility.md(Binarybun.lockbrow) promises "vendor --revertreturns the pre-hosted lock", and the vendored section says rollback "restores the original manifest / lock bytes, removes the.socket/vendorstate". The vendor state holds everything needed to restore the registry tuple: name, version, the registry resolution and the integrity in thebun_lockb_packageoriginal. The text-lock path already restores exactly this shape on a native text lock. If socket-patch must refuse, it should name a remedy that works, and the hosted takeover shouldn't exit 0 with a circular hint. A re-vendor should never discard a recorded original just because the lock changed format. - Actual: see above. Revert/rollback exit 1 (case 1), or exit 0 with nothing reverted and the pre-vendor original lost (case 2).
Matrix (Linux, main 045d7ec)
bun.lockb writer |
migrated by --save-text-lockfile |
Case 1 (revert / rollback / hosted takeover) | Case 2 (re-vendor → revert) |
|---|---|---|---|
| 1.1.45 | 1.2.23 (v1) | fail (1 / 1 / 0, nothing done) | untested |
| 1.1.45 | 1.4.2 (v2) | fail | fail (still patched after bun install) |
1.2.23 (saveTextLockfile = false) |
1.2.23 / 1.4.2 | fail | untested |
| 1.2.23 | 1.3.14 (v1) | untested | fail |
1.4.2 (saveTextLockfile = false) |
1.2.23 / 1.4.2 | fail | fail (1.4.2) |
control: text bun.lock from the start, 1.4.2 |
— | n/a | pass (revert byte-exact) |
control: bun.lockb not migrated, writers 1.1.45 / 1.4.2 |
— | n/a | pass (registry bytes after bun install) |
macOS/Windows: untested (the code paths are OS-independent).
First bad version: not a regression. Release 4.0.0 refused --mode vendored on bun.lockb (exit 1), so the migration never arose there.
Suspect code
crates/socket-patch-core/src/vendor/state.rs:453-473,carry_forward_wiring: an original is carried forward only from a previous record with a matching surface (wiring_surface_matches), so abun_lockb_package/bun.lockboriginal never reaches the newbun_lock_package/bun.lockrecord.crates/socket-patch-core/src/vendor/bun_lock.rs:536: rewriting "our own" vendored tuple recordsoriginal: Noneby design, relying on that carry-forward.crates/socket-patch-core/src/vendor/bun_binary.rs:419-426,revert: a missingbun.lockbis a hard failure even whenbun.locknow holds the recorded vendored tuples.
Activity
mikolalysenko commentedon Oct 4, 2026
[agent] Triage: priority:p1 (Bun). No duplicate or existing fix found. Confirmed on main 045d7ec:
carry_forward_wiring(vendor/state.rs) only carries an original across a matching wiring surface, so abun_lockb_packagerecord never reaches the newbun.lockrecord, andbun_binary::reverttreats a missingbun.lockbas a hard failure even whenbun.lockholds the recorded vendored tuples. Not clustered: no other open issue shares this lock-format migration path.Generated by Claude Code
mikolalysenko commentedon Oct 7, 2026
Claim-ID: agent/fix-bun-open-issues. Draft fix PR: #1009 (it covers all open
pm:bunissues).Revert vendored bun.lockb after Bun migrates it to bun.lock (#784)
Check out migrated bun.lock fixtures byte-exact (#784)
Revert same-uuid re-pins on a migrated bun.lock (#784)
Reconcile #861 with #784's migrated-lock fixture golden entry
Reconcile #764 with #784's migrated-lock revert tests
Cover re-vendor and re-run after a bun.lock migration end to end (#784)