worker_threads: keep error.code when the thrown value cannot be cloned - #34509
Closed
cirospaciari wants to merge 1 commit into
Closed
cirospaciari wants to merge 1 commit into
cirospaciari wants to merge 1 commit into
Conversation
A worker that throws something structured-clone can't serialize falls back to
sending only the message text, and the parent rebuilds a bare Error from it —
losing `code`. Bun's own ResolveMessage is exactly that case: it carries the
right code and is not even an Error instance.
new Worker(`require("node:internal/freelist")`, { eval: true })
node: code ERR_UNKNOWN_BUILTIN_MODULE
bun : code undefined (the worker-side value has the right code)
Carry the code alongside the message instead of replacing the value. Replacing
it was the first attempt and it broke `support require in eval for a file that
doesnt exist`: rebuilding from ResolveMessage's own .message drops Bun's
"error: ..." prefix, which that test asserts on. The message text is now
untouched — only `code` is added.
The read is shared with the value path as Worker::errorCodeOf, under a top
exception scope since a `code` getter can run JS.
test-worker-internal-modules.mjs: 3 fail -> 3 pass, and 0/2 without the change.
Vendored test-worker* 106 pass/2 fail (both pre-existing: arraybuffer-zerofill
needs `bun test`, on-process-exit is debug-only). Thrown errors keep their code
as before, and test-worker-error-stack-getter-throws still passes.
Collaborator
|
Updated 4:07 PM PT - Jul 17th, 2026
⏳ @cirospaciari, your commit 56d0a5b is still building in
|
Contributor
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
Member
Author
|
Folding this into #34424 — three stacked PRs was more confusing than it was worth. Same commits, same tests, one review. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #34424 — review that first; this PR is the last two commits only.
A worker that throws something structured-clone can't serialize falls back to sending only the message text, and the parent rebuilds a bare
Errorfrom it — losingcode. Bun's ownResolveMessageis exactly that case: it carries the right code and isn't even anErrorinstance (isError: false), so it neither clones nor hits theErrorInstanceretry path.The code isn't missing — Bun sets it correctly, and the same require on the main thread reports
ERR_UNKNOWN_BUILTIN_MODULE. It's lost only crossing the thread boundary. This affects every coded error a worker throws that isn't cloneable, not just this one.What it does
Carries
codealongside the message rather than replacing the value, and shares the read with the value path asWorker::errorCodeOf(under a top exception scope, since acodegetter can run JS).Replacing the value was my first attempt and it was wrong. Rebuilding an
ErrorfromResolveMessage's own.messagedrops Bun's"error: ..."prefix, whichsupport require in eval for a file that doesnt existasserts on — it went from"error: Cannot find module..."to"Error: Cannot find module...". The gate caught it. The message text is now byte-identical to before; onlycodeis added.Verification
test-worker-internal-modules.mjs.codeundefinedERR_UNKNOWN_BUILTIN_MODULE(= node).codeE_CUSTOME_CUSTOM(unchanged)Vendored
test-worker*: 106 pass / 2 fail — both pre-existing (arraybuffer-zerofillneedsbun test;on-process-exitis debug-only). Bun'sworker_threadssuite back to its 2 known failures.test-worker-error-stack-getter-throwsstill passes (same function).Why stacked rather than in #34424
#34424 is already 22 source files / 820 insertions / 17 commits across the CLI parser, TLS/CA, cpu-prof, worker_threads and async_hooks. It's at the limit of what's reasonable to review in one pass, and landing is what actually delivers compatibility. This is a separate, self-contained bug with its own test, so it gets its own PR.