Repository navigation
Hosted pin on a bun.lockb record that Bun shares with a bundled copy can't be unwound: list errors, and the vendored takeover fails (#1008's #828 fix covers the text bun.lock only) #1243
Description
[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).
Summary
A Bun project installs left-pad@1.3.0 twice: once as a direct registry dependency, and once bundled inside another package (bundledDependencies). Bun's binary bun.lockb (1.2.x and later) keeps one package record for left-pad@1.3.0 and marks it as also bundled. A hosted scan wires that record, because the redirect writer handles shared records on purpose: "one Bun shares with a regular install is still redirected for that install". It warns redirect_bun_bundled_instance_skipped ("is also bundled…") and exits 0. The fresh install is correct: the direct copy is patched and the bundled copy is not.
After that, socket-patch can't manage the pin it just wrote. This is the #828 failure, which #1008 fixed for npm and for Bun's text bun.lock, but not for bun.lockb:
listexits 1 withhosted_wiring_contested("bun.lockb: package Remove tsc from npm prepare script #1: pkg:npm/left-pad@1.3.0 is wired to a Socket patch, but bun installs this entry as a bundled dependency…"). Its remedy, "re-runsocket-patch scan --mode hosted", writes the same state again.- The hosted → vendored takeover (
scan --mode vendored) exits 1,partial_failure,vendor_lock_entry_not_found: "bun.lockb has no registry entry for left-pad@1.3.0". The hosted pin is never recognized, so it's never restored before vendoring. removeandrollbackrefuse it on the samehosted_wiring_contestedpath. A hostedbun.lockbrollback is documented to refuse with thegit checkout -- bun.lockbremedy, but here the reason given is contested wiring.
The same project with a text bun.lock passes on the current main: list succeeds, the takeover vendors, and vendor --revert restores the pre-hosted lock byte for byte. That shows the #828 fix works for text locks.
Impact
A user with a bundled duplicate (Bun's lockb merges it with the regular install) who tries hosted mode can't list the pin or move to vendored mode, and the remedy it prints loops. The only way out is git checkout -- bun.lockb. VEX is not affected: discovery withholds the attestation, which is correct while the bundled copy stays unpatched.
Repro (Linux, Bun 1.4.2; patch API mocked locally)
# a parent package that bundles left-pad@1.3.0
mkdir -p bparent/package/node_modules/left-pad && cd bparent/package
echo '{"name":"bparent","version":"1.0.0","dependencies":{"left-pad":"1.3.0"},"bundledDependencies":["left-pad"]}' > package.json
echo 'module.exports=require("left-pad")' > index.js
curl -sL https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz | tar xz --strip-components=1 -C node_modules/left-pad
cd .. && tar czf bparent-1.0.0.tgz package && cd ..
mkdir proj && cd proj && cp ../bparent/bparent-1.0.0.tgz .
echo '{"name":"bt","version":"1.0.0","dependencies":{"left-pad":"1.3.0","bparent":"file:./bparent-1.0.0.tgz"}}' > package.json
printf '[install]\nsaveTextLockfile = false\n' > bunfig.toml
bun install # writes bun.lockb: one left-pad@1.3.0 record, also bundled
git init -q && echo node_modules/ > .gitignore && git add -A && git commit -qm init
socket-patch scan --mode hosted --json # exit 0, redirected 1, redirect_bun_bundled_instance_skipped ("also bundled")
git add -A && git commit -qm hosted
socket-patch list --json # exit 1, hosted_wiring_contested (patched_ref_unattributable … bundled dependency)
socket-patch scan --mode vendored --json # exit 1, partial_failure, vendor_lock_entry_not_foundWith bunfig.toml removed (text bun.lock, which has separate "left-pad" and "bparent/left-pad" entries with { "bundled": true }), list exits 0 and the takeover and vendor --revert succeed.
Expected vs actual
- Expected: a pin the hosted scan wrote is listed and unwound like any other hosted pin.
CLI_CONTRACT.md("Unattested references") and Fix open npm issues #1008's npm hosted pin next to a bundled copy can't be unwound: rollback/remove refuse it, and the vendored takeover skips the restore, so vendor --revert lands back on hosted and allow-remote=all stays #828 fix say refs withheld from attestation only because an unpatched bundled copy sits beside them go toDiscovery::shadowed: never attested, but visible toHostedPin::all, so list, rollback, remove and the vendored takeover handle them. Fix open npm issues #1008 names "Bun … bundled copies" as fixed the same way. - Actual: for
bun.lockb, the ref is diagnosedpatched_ref_unattributableand dropped. It isn't shadowed, so every management command refuses it as contested.
Matrix (Linux; current main 60300b8; reproduced twice on 1.4.2)
| Bun | lock | hosted scan | list | hosted → vendored takeover |
|---|---|---|---|---|
| 1.1.39 | bun.lockb | exit 0, no bundled flag recorded | pass | pass |
| 1.2.23 | bun.lockb | exit 0, "also bundled" | exit 1 contested | exit 1 vendor_lock_entry_not_found |
| 1.3.9 | bun.lockb | exit 0, "also bundled" | exit 1 | exit 1 |
| 1.4.2 | bun.lockb | exit 0, "also bundled" | exit 1 | exit 1 |
| 1.2.23 / 1.3.9 / 1.4.2 | text bun.lock | exit 0 | pass | pass (revert byte-exact) |
macOS and Windows: untested (the format is the same; no probe run).
First bad
This isn't a regression. Before #1008 (793edd4), both the text lock and bun.lockb failed this way. #1008 (f3c6313) fixed the text lock only.
Suspect code
crates/socket-patch-core/src/vex/discover/bun.rs:287:if p.bundled { bundled.record(…) }routes any record a bundled edge reaches, including one Bun shares with a regular install (bundled_only == false), intoBundled::record.crates/socket-patch-core/src/vex/discover/bun.rs:186-201:Bundled::recordturns that record's ref into aDIAG_REF_UNATTRIBUTABLEdiagnostic and drops it, rather thanout.shadow(r)(whichBundled::contest, line 242, does for the text lock's separate regular entry).crates/socket-patch-core/src/patch/redirect/bun_binary.rs:77-92: the writer deliberately wires shared records (if p.bundled_only { continue; }), so the reader and the writer disagree about them.
Related: #828 (npm, closed by #1008), #469 (bundled copies in vendored mode).
Activity
mikolalysenko commentedon Oct 9, 2026
[agent] Triage:
priority:p1(Bun, npm family). Confirmed on main:vex/discover/bun.rssends every record a bundled edge reaches intoBundled::record, including abun.lockbrecord Bun shares with a regular install (bundled_only == false). That turns its ref intoDIAG_REF_UNATTRIBUTABLEand drops it, where the text-lock path shadows it. Meanwhileredirect/bun_binary.rsdeliberately wires shared records. No open PR covers this; #1009 and #1161 cover other Bun issues.Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
[agent] Claiming this issue (shared root cause: bun.lockb discovery drops the ref of a record Bun shares between a regular and a bundled install instead of shadowing it). Branch: agent/fix-bun-lockb-shared-bundled-shadow. Claim-ID: 2026-10-09T08:21:15Z-9b5ab2
Generated by Claude Code
mikolalysenko commentedon Oct 9, 2026
[agent] Draft PR: #1247
Generated by Claude Code
Keep bun.lockb shared bundled pins manageable
Test a hosted pin on a shared bundled bun.lockb record
Run the shared bundled bun.lockb test on Bun 1.4
mikolalysenko commentedon Oct 9, 2026
v5 triage: P2, not a release blocker. Retain legacy binary Bun shared/bundled-record management at P2. The current text-lockfile workflow takes precedence; PR #1247 is pending.
This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.