Skip to content

Bun 1.3.0 and 1.3.1 locks have no configVersion, so a "!"-excluded member is still refused in hosted and vendored mode after the #1492 fix (regression since #1480) #1521

Closed

Description

[agent] Found by the scheduled Bun bug-hunt routine (ledger #306).

Summary

#1480 (#1097) decides whether a Bun workspace root honours ! patterns from the root lock. A bun.lock with a top-level configVersion, or a bun.lockb with the cNfGvRsN trailer (added by #1496 for #1492), counts as Bun 1.3+. Anything else counts as pre-1.3, which ignores !. But Bun 1.3.0 and 1.3.1 already honour !, and neither writes configVersion or the cNfGvRsN trailer. Bun 1.3.2 is the first release that writes them. So the #1492 symptom is still there for every lock written by 1.3.0 or 1.3.1, text and binary alike:

  • A hosted scan from the excluded member (which has its own lock) fails with redirect_workspace_lockfile_elsewhere. The message is false: it says Bun "installs it from /bun.lock and ignores its own ./bun.lock", but the root lock doesn't list the member at all.
  • A vendored scan from the member fails with vendor_lockfile_missing.
  • The suggested root run exits 0 with success and skips the package as redirect_unconfirmed. Nothing gets pinned anywhere.

These locks stay untagged on newer Bun as long as CI only runs bun install --frozen-lockfile. A plain bun install on 1.3.2+ adds "configVersion": 0 and works around it.

Impact

On Bun 1.3.0/1.3.1, and on any project whose lock was last written by those versions, hosted and vendored modes can't patch a project excluded with !, from either directory. 5.0.0 and the commit before #1480 patch it fine.

Repro (Linux, socket-patch bb73e2f, Bun 1.3.0)

mkdir -p w/packages/a w/packages/excluded && cd w && git init -q
echo 'node_modules/' > .gitignore
echo '{"name":"root","private":true,"workspaces":["packages/*","!packages/excluded"],"dependencies":{"minimist":"1.2.5"}}' > package.json
echo '{"name":"a","version":"1.0.0","dependencies":{"minimist":"1.2.5"}}' > packages/a/package.json
echo '{"name":"excluded","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > packages/excluded/package.json
bun install && (cd packages/excluded && bun install)   # Bun 1.3.0
grep -c '"packages/excluded"' bun.lock                  # 0: Bun excluded it
grep -c configVersion bun.lock                          # 0: untagged
git add -A && git commit -qm init
cd packages/excluded && socket-patch scan --mode hosted --json
# status "error", error.code redirect_workspace_lockfile_elsewhere, exit 1
socket-patch scan --mode vendored --json                # partialFailure, vendor_lockfile_missing, exit 1
cd ../.. && socket-patch scan --mode hosted --json      # success, left-pad skipped redirect_unconfirmed, exit 0

For the bun.lockb variant, add bunfig.toml with [install] saveTextLockfile = false at the root and in the member. Patch data came from a local mock of the patch API (--api-url <mock> --org o --api-token fake, with SOCKET_PATCH_SERVER_URL set to the mock). The oracle was a fresh clone plus a cold-cache bun install --frozen-lockfile in packages/excluded, then checking node_modules/left-pad/index.js for the patch marker.

Expected vs actual

CLI_CONTRACT.md (redirect_workspace_lockfile_elsewhere) says the refusal applies only when "the nearest ancestor package.json whose workspaces … matches the directory", and that "a ! pattern excludes what earlier patterns matched for … Bun 1.3+". The member isn't in Bun 1.3.0's workspace, so it's a standalone project, and its own lock should be pinned, as it is on 1.3.2+. Actual: the member is refused, and the root run reports success without pinning anything.

Matrix (Linux, 2 runs each)

Bun writing the locks lock member hosted member vendored root hosted frozen clone of member
1.2.23 text / lockb n/a (Bun ignores !; the member really is a member) n/a — —
1.3.0 text / lockb refused refused success, nothing pinned unpatched
1.3.1 text / lockb refused refused success, nothing pinned unpatched
1.3.2 / 1.3.3 text / lockb (writes configVersion / cNfGvRsN)
1.3.9 / 1.4.3 text / lockb pinned vendored — patched
1.2.23 lockb upgraded by a 1.4.3 bun install lockb pinned — — patched

macOS and Windows are untested; the logic doesn't depend on the OS.

First bad commit

Suspect code

crates/socket-patch-core/src/hosted/governing_root.rs:555-590 (lock_dialect). The doc comment says "a lock without it, as Bun 1.3.0 and earlier write, reads as older Bun", but 1.3.0 and 1.3.1 honour !. One possible signal for an untagged lock: whether the root lock's workspaces map (or the lockb workspace list) actually contains the candidate directory. Bun ≤ 1.2 always lists a matched member there, and 1.3.0/1.3.1 don't list an excluded one.

Related: #1492, #1097, #1101.

Activity

  1. added a commit that references this issue on Oct 14, 2026
  2. mikolalysenko commented on Oct 14, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Triage: priority:p1 (Bun, npm family). This is not a duplicate. #1492 / #1496 taught lock_dialect to read the cNfGvRsN trailer in a bun.lockb, but neither covers locks that Bun 1.3.0 / 1.3.1 write with no tag at all. No open PR covers it.

    Confirmed in code on main 313d532: crates/socket-patch-core/src/hosted/governing_root.rs lock_dialect returns BUN_PRE_1_3 for any bun.lock without a top-level configVersion and any untagged bun.lockb. package_json_workspace_root then counts the !-excluded member as governed by the root lock. Unclustered: the cause is local to the Bun dialect probe.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 14, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Claiming this issue (shared root cause: untagged Bun 1.3.0/1.3.1 locks read as the pre-1.3 workspaces dialect). Branch: agent/fix-bun-untagged-lock-dialect. Claim-ID: 2026-10-14T06:21:27Z-5cc33c


    Generated by Claude Code

  4. mikolalysenko commented on Oct 14, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Draft PR: #1523


    Generated by Claude Code

  5. added 3 commits that reference this issue on Oct 14, 2026
    8dfd5b2
    97c8023
    ea8578d
  6. mikolalysenko commented on Oct 14, 2026

    @mikolalysenko
    CollaboratorAuthor

    [agent] Verified fixed by #1523 on main a3f56f7 with real Bun on Linux. The setup is a !packages/b-excluded member that has its own lock, scanned from the member:

    Writer lock hosted vendored cold --frozen-lockfile in a fresh clone
    1.3.0 text success, member lock pinned success patched (1.3.0 reader and 1.4.3 reader)
    1.3.0 bun.lockb success success patched (1.3.0 and 1.4.3)
    1.3.1 text success success patched
    1.3.1 bun.lockb success success patched

    No refusal fired (redirect_workspace_lockfile_elsewhere / vendor_lockfile_missing), and the root lock was left untouched.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions