Skip to content

bun run build fails at build:v2 on clean master: @opencode/plugin's optional-entry probe re-throws because Bun's ResolveMessage is not instanceof Error #446

Description

@iceteaSA

Summary

bun run --cwd packages/plugin build fails at its final build:v2 step on clean upstream/master, so bun run build never exits 0:

$ cd /tmp/mc-upstream-cmp && git rev-parse --short HEAD
dc952bf3

$ bun run --cwd packages/plugin build:v2
ResolveMessage: Cannot find module '/tmp/mc-upstream-cmp/packages/plugin/server' from '/tmp/mc-upstream-cmp/packages/plugin'
      at entry (…/@opencode/plugin/dist/host.js:24:27)
      at resolve (…/@opencode/plugin/dist/host.js:29:22)
      at <anonymous> (packages/plugin/src/v2/server.test.ts:50:30)
(fail) union entry satisfies both loaders without a ./server override
 3 pass · 1 fail
error: script "build:v2" exited with code 1

Fresh /tmp worktree off master, real bun install, no fork code.

Note the build bundle is fine — build:v2 runs last, after dist/index.js is emitted, so the artifact exists and loads correctly. Only the exit code is red. Worth knowing if CI gates on it, and worth not mistaking a stale dist for a fresh one when the build "fails".

Cause

server.test.ts:50 calls Host.resolve(...), which probes optional entry subpaths ["server", ""] and is designed to swallow not-found and return undefined. The guard in @opencode/plugin@2.0.3 dist/host.js:14-24:

catch (error) {
    if (!(error instanceof Error) ||
        !("code" in error) ||
        !["ENOENT","ENOTDIR","MODULE_NOT_FOUND","ERR_MODULE_NOT_FOUND",
          "ERR_PACKAGE_PATH_NOT_EXPORTED","ERR_UNSUPPORTED_DIR_IMPORT"].includes(String(error.code)))
        throw error;
}

Under bun, resolveModule is Bun.resolveSync (@opencode/util maps #runtime-import./dist/runtime/import.bun.js under the bun condition). Probing the absent subpath:

$ bun -e "try { Bun.resolveSync(dir + '/server', dir) } catch (e) { … }"
server threw: ResolveMessage  code= "ERR_MODULE_NOT_FOUND"  instanceof Error: false  in swallow list: true

The code is correct and is in the listERR_MODULE_NOT_FOUND. The failure is the first clause: Bun's ResolveMessage is its own class and is not instanceof Error, so !(error instanceof Error) is true, the || short-circuits, and it re-throws before the code list is ever consulted.

I want to flag that I initially assumed the opposite — that bun was emitting a code outside the list — and that guess was wrong. The list is fine; the type check is what rejects it. Anyone reading the stack trace is likely to land on the same wrong hypothesis, so it seems worth stating explicitly.

Why this is arguably upstream's to route, not just a vendor bug

The defect lives in @opencode/plugin@2.0.3, but it is reachable only because a bun-run test drives a resolver designed around Node's error shapes. Options as I see them, without a strong opinion on which is right:

  • Report upstream to @opencode/plugin — the durable fix is duck-typing the error (typeof error === "object" && error && "code" in error) instead of instanceof Error, since bun's resolver is a first-class target for that package.
  • Have server.test.ts tolerate the bun shape, so the repo's own build is not gated on a third-party type check.
  • Pin/patch the dependency until it lands upstream.

Environment

Clean upstream/master dc952bf3, dedicated /tmp worktree, bun install from lockfile, Bun 1.3.14, Linux x64, @opencode/plugin@2.0.3, @opencode/util@2.0.3. Reproduced identically on our fork tree, which does not touch src/v2/, package.json exports, index.js, or bun.lock — all four are byte-identical to upstream at that sha.

Activity

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions