Repository navigation
Description
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 list — ERR_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 ofinstanceof Error, since bun's resolver is a first-class target for that package. - Have
server.test.tstolerate 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
magic-alfonso commentedon Sep 17, 2026
Shipped in v0.42.4 alongside #445: the v2 entry test tolerates Bun's resolve-message shape and
build:v2succeeds on a clean checkout at the declared Bun floor. Closing.