Repository navigation
On Bun 1.4, a bun patch made on a hosted or vendored package is silently dropped by the next superseding re-run, takeover, rollback or revert (the #367 guard only matches name@version keys) #1019
Description
[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).
Summary
#873 (fix for #367) leaves a package on its registry entry when the root package.json / bun.lock patchedDependencies has a key for its name@version or bare name. But on Bun 1.4.x, running bun patch <pkg> after socket-patch has rewired the package keys the user's patch by the package's current resolution:
"patchedDependencies": {
"plainpkg@https://patch.socket.dev/patch/npm/plainpkg/1.0.0/<tok>/<uuid>/plainpkg-1.0.0.tgz": "patches/plainpkg@https%3A%2F%2F…tgz.patch"
}(vendored: "plainpkg@.socket/vendor/npm/<uuid>/plainpkg-1.0.0.tgz"). Bun 1.4.2 applies that patch on top of the Socket-patched bytes, so the project has both fixes. patched_dependency_key matches neither spelling, so every later socket-patch operation that changes the resolution rewrites the entry, exits 0 with no warning, and orphans the key. Bun then silently ignores the orphaned key on every install, so the user's own patch is gone.
Impact
This is the same silent loss #367 fixed, reached through the normal order of events: patch with socket-patch first, bun patch something else in that package later. A routine hosted re-run that picks up a superseding Socket patch (new uuid → new URL) is enough. CI frozen installs succeed, vex attests the Socket patch, and nothing flags that the project's own patch stopped applying.
Repro (Linux, main db83f01, Bun 1.4.2)
Local npm registry on :4873 (bunfig [install] registry) and a patch-API mock on :4874 (SOCKET_PATCH_SERVER_URL), serving plainpkg@1.0.0 with a Socket patch.
printf '[install]\nregistry = "http://127.0.0.1:4873/"\n' > bunfig.toml
echo '{"name":"proj","version":"1.0.0","dependencies":{"plainpkg":"1.0.0","otherpkg":"2.0.0"}}' > package.json
bun install && git init -q && echo node_modules > .gitignore && git add -A && git commit -qm init
socket-patch scan --mode hosted --yes # plainpkg → hosted URL tuple
git add -A && git commit -qm hosted
bun patch plainpkg && echo '// USERPATCH' >> node_modules/plainpkg/index.js
bun patch --commit node_modules/plainpkg # key: "plainpkg@http://…/tok/<uuid>/plainpkg-1.0.0.tgz"
git add -A && git commit -qm bunpatch
# fresh clone + cold `bun install --frozen-lockfile`: index.js = PATCHED + "// USERPATCH" (both apply)
# the Socket patch is superseded by a new uuid, then the usual re-run:
socket-patch scan --mode hosted --yes --json # exit 0, status success, warnings []
git commit -qam rerun
# fresh clone + cold `bun install --frozen-lockfile`: exit 0, index.js = PATCHED only, "// USERPATCH" gonebun.lock still has the old-URL patchedDependencies key; the package line now names the new URL.
Expected vs actual
- Expected (docs/testing/bun-compatibility.md, the Hosted and vendored Bun rewiring silently discards the project's own
bun patch(patchedDependencies): fresh frozen installs drop the user's patch with exit 0 #367 row): a package the project patches withbun patchis never rewired in a way that "would silently drop that patch from every install with exit 0". The run should warnredirect_bun_patched_dependency_skipped(hosted) or refusevendor_lock_entry_unsupported(vendored), naming the key. Rollback/revert should at least warn that the key will stop applying. The row's premise, "Bun applies the user's patch only to the registryname@version", doesn't hold on Bun 1.4: Bun keys and applies patches on URL and local-tarball resolutions too. - Actual: exit 0,
status: success, no warning code at all; the user's patch silently stops applying.
Matrix (Linux, cold-cache fresh clone after each step; "drop" = USERPATCH lost, exit 0, no warning)
| Bun | lock | start | bun patch key |
Operation | Result |
|---|---|---|---|---|---|
| 1.4.2 | text v2 | hosted | name@<hosted url> |
hosted re-run, superseding uuid | drop (×2) |
| 1.4.2 | bun.lockb |
hosted | name@<hosted url> |
hosted re-run, superseding uuid | drop |
| 1.4.2 | text v2 | hosted | name@<hosted url> |
scan --mode vendored (takeover) |
drop (×2) |
| 1.4.2 | bun.lockb |
hosted | name@<hosted url> |
scan --mode vendored (takeover) |
drop |
| 1.4.2 | text v2 | hosted | name@<hosted url> |
rollback |
drop (×2; only reinstall_required) |
| 1.4.2 | text v2 | vendored | name@.socket/vendor/…tgz |
vendored re-run, superseding uuid | drop |
| 1.4.2 | text v2 | vendored | name@.socket/vendor/…tgz |
scan --mode hosted (takeover) |
drop (only redirect_takeover_reverted_vendored) |
| 1.4.2 | text v2 | vendored | name@.socket/vendor/…tgz |
vendor --revert |
drop |
| 1.4.2 | text v2 | registry | name@1.0.0 |
hosted / vendored scan | pass (#873 guard fires) |
| 1.2.23, 1.3.9 | text v1 | hosted | — | — | n/a: Bun's own bun patch --commit crashes (SIGILL) on a URL-resolved package, so the state can't be created |
| macOS / Windows | — | — | — | — | untested (no probe branches this run); the key match is platform-independent string logic |
First bad: not a regression, a gap in #873's matching. 4.0.0 predates the guard entirely (#367).
Suspect code
crates/socket-patch-core/src/vendor/bun_lock_text.rs:123patched_dependency_keyonly matches"{name}@{version}"or"{name}". Keys"{name}@{current resolution}"(hosted URL /.socket/vendor/…path) are ignored.- Callers:
crates/socket-patch-core/src/patch/redirect/mod.rs:4813skip_bun_user_patched(text + binary hosted),crates/socket-patch-core/src/vendor/bun_lock.rs:689(vendored), and nothing on the rollback /vendor --revert/ takeover-unwind paths. - Possible direction: treat any key whose name part is the package and whose spec part equals the entry's current resolution (or any URL / path spec for that name) as user-patched; keep the entry and warn, or refuse with the
bun patch --commitremedy.
Not covered by the open draft #1009 (its scope is the earlier pm:bun issues).
Activity
mikolalysenko commentedon Oct 7, 2026
[agent] Triage:
priority:p1. Bun (npm-family). Not a duplicate: #367 / #873 cover onlyname@versionand bare-namekeys, while this report is about Bun 1.4 keyingpatchedDependenciesby the rewired resolution. No open agent PR covers it yet. Draft #1009 is the open bun sweep, but its issue list does not include this one.Generated by Claude Code
bun: run 28 ledger (#1019 filed; #367/#884/#831/#963 verified on Bun)
mikolalysenko commentedon Oct 9, 2026
v5 triage: P2, not a release blocker. Retain coexistence with a later bun patch at P2. Do not close a real user-patch preservation issue, but keep it outside the base lockfile release gate.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.
mikolalysenko commentedon Oct 12, 2026
[agent] Re-triage (Bun bug-hunt run 38, ledger #306): this still reproduces on main
4e146ddwith Bun 1.4.3, the new stable release, on Linux with a textbun.lockv2.minimist@1.2.2to uuid A.bun patch minimist, then append// USERPATCH, thenbun patch --commit. This writes the key"minimist@http://…/tok/<A>/minimist-1.2.2.tgz". A fresh frozen clone has bothSOCKET-PATCHED-MM-AandUSERPATCH.successandwarnings: [].SOCKET-PATCHED-MM-B, andUSERPATCHis gone.Bun 1.4.3 still keys a post-rewire
bun patchby the URL resolution, so the guard gap described above still applies.Generated by Claude Code