Skip to content

worker: re-throw TerminationException from Bun__reportUnhandledError so terminate() breaks a microtask-bound ReadableStream loop - #36806

Open
robobun wants to merge 5 commits into
mainfrom
claude/farm/ed614daa/worker-terminate-microtask-readablestream
Open

worker: re-throw TerminationException from Bun__reportUnhandledError so terminate() breaks a microtask-bound ReadableStream loop#36806
robobun wants to merge 5 commits into
mainfrom
claude/farm/ed614daa/worker-terminate-microtask-readablestream

worker: re-throw TerminationException from Bun__reportUnhandledError …

303382e
Select commit
Loading
Failed to load commit list.
Claude / Claude Code Review completed Aug 3, 2026 in 23m 33s

Code review found 1 important issue

Found 3 candidates, confirmed 2. See review comments for details.

Details

Severity Count
🔴 Important 1
🟡 Nit 1
🟣 Pre-existing 0
Severity File:Line Issue
🔴 Important src/jsc/virtual_machine_exports.rs:120-123 EventEmitter listener loop can trip assertNoException() after re-throwing TerminationException
🟡 Nit test/js/web/workers/worker-terminate-lifetime.test.ts:221-231 Dangling Bun.sleep(deadline) timers keep test subprocess alive after PASS

Annotations

Check failure on line 123 in src/jsc/virtual_machine_exports.rs

See this annotation in the file changed.

@claude claude / Claude Code Review

EventEmitter listener loop can trip assertNoException() after re-throwing TerminationException

Now that `Bun__reportUnhandledError` re-throws the TerminationException, `EventEmitter::innerInvokeEventListeners` (src/jsc/bindings/webcore/EventEmitter.cpp:259) can return from the report call with the exception pending and then continue the loop into the next listener's `JSC::call()`, tripping `executeCallImpl`'s `assertNoException()` and SIGABRTing the process in debug builds. Previously the report call was a no-op for termination, so this is a regression at that one caller — add a `if (vm.i

Check warning on line 231 in test/js/web/workers/worker-terminate-lifetime.test.ts

See this annotation in the file changed.

@claude claude / Claude Code Review

Dangling Bun.sleep(deadline) timers keep test subprocess alive after PASS

The `Bun.sleep(${deadline})` loser of each `Promise.race` is never cancelled, so after `console.log("PASS")` the subprocess idles until the last-armed timer fires — ~4s on release, ~10s on debug/ASAN — before it can exit. Add `process.exit(0)` after `console.log("PASS")` (or race a clearable `setTimeout` and clear it when `terminate()` wins) to shave that dead time from every CI run.