Conversation
WalkthroughChangesError conversion now selects visible original error frames and falls back to wrapper throw-site frames when needed. New process and worker tests verify stack preservation. Existing snapshots update caret positions and stack locations. Error stack preservation
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
Full details: Out of Scope Changes checkExplanation The implementation, regression tests, worker coverage, and snapshot updates are related to consistent original-stack selection and the resulting diagnostic positions. No unrelated code changes are evident. Full details: Description checkExplanation The description explains the problem, cause, fix, background, regression coverage, and verification results. It does not use the exact template headings, but it provides the required information in equivalent sections. Comment |
|
Found 3 issues this PR may fix:
🤖 Generated with Claude Code |
|
Checked the three suggestions against this build:
|
|
This PR may be a duplicate of:
🤖 Generated with Claude Code |
There was a problem hiding this comment.
No bugs found, but this reorders the stack-source preference in fromErrorInstance — a runtime-wide change to what every uncaught-error report points at (four snapshot updates confirm the ripple), and it overlaps with #30508. Worth a human look at whether the new priority (ErrorInstance::stackTrace() → parsed .stack → wrapper stack) is the ordering we want everywhere.
Checked: the two populateStackTrace passes stay coherent — parsed-.stack frames get jsc_stack_frame_index = -1 via the ZigStackFrame default ctor, so collectSourceLines skips them rather than indexing the wrong vector; the new wrapper-stack fallback only fires when frames_len == 0 so it can't clobber parsed frames; FinalizerSafety::MustNotTriggerGC is passed on the new err->stackTrace() paths as before.
Extended reasoning...
Overview
Reorders stack-trace source selection in src/jsc/bindings/ZigException.cpp's fromErrorInstance and ZigException__collectSourceLines so an Error's own captured/carried stack is preferred over the JSC::Exception wrapper's throw-site stack. Adds two subprocess tests in worker_threads.test.ts and updates four existing snapshots whose caret column moves from the throw bytecode position to the Error constructor position.
Security risks
None. This is display-only logic in the crash reporter; no new user-controlled input reaches allocation or side effects.
Level of scrutiny
High. fromErrorInstance is on the path of every uncaught-exception / unhandled-rejection print in the runtime. The change is small in lines but broad in effect: it alters which frame vector (and therefore which file:line:col and source preview) is shown for any thrown ErrorInstance, not just the worker/clone case that motivated it. The four unrelated snapshot updates are evidence of that reach. It also overlaps with open PR #30508, so a maintainer should decide which ordering lands and whether the two need reconciling.
Other factors
- Verified the two-pass invariant the new comment documents:
OnlySourceLinesindexesjsc_stack_frame_index, and V8-string-parsed frames default that field to-1(via theZigStackFrame()ctor inheaders-handwritten.h), so theelse if (jscException->stack()...)branch incollectSourceLinesis a harmless no-op for the cloned-.stackcase rather than a mismatched index into the wrapper vector. - The fallback block checks
except.stack.frames_len == 0before repopulating from the wrapper stack, so it cannot overwrite frames produced by the.stackparser;getFromSourceURL = falsethere is correct givenframes_lenwill be non-zero afterward. - New tests follow harness conventions (spawned subprocess, drained pipes, exit-code asserted last) and assert both the presence of the worker frame and the absence of
node:events/rethrowIt, so they fail on main for the right reason. - Open question a human should weigh: for
const e = new Error(); /* far away */ throw e;in user code, this now points at construction rather than the throw site. That matches Node'serr.stack, but it is a visible change; the PR description acknowledges it only via the snapshot updates.
8408afb to
864ec48
Compare
There was a problem hiding this comment.
Beyond the inline nit, I also checked whether ZigException__collectSourceLines can cross-contaminate string-parsed frames with wrapper-stack source lines in the cloned-error case — it can't, because current = {} runs ZigStackFrame's default ctor which sets jsc_stack_frame_index = -1, and the OnlySourceLines loop skips negative indices. Deferring to a human because the reorder shifts the reported caret for every throw new Error(...) (four snapshots updated here; there may be others across the suite) and overlaps open PR #30508.
Extended reasoning...
Verified the two-pass interaction between fromErrorInstance (OnlyPosition) and ZigException__collectSourceLines (OnlySourceLines) for the new case where frames come from the V8 .stack string parser while a non-empty wrapper stack also exists. The string-parsed frames get jsc_stack_frame_index = -1 via the ZigStackFrame() default constructor (headers-handwritten.h:211), so when collectSourceLines falls to the jscException->stack() branch, its OnlySourceLines loop skips every frame and no wrong source preview is emitted. Not approving because this is a global change to the uncaught-error caret position that a maintainer should sign off on, and it supersedes/overlaps #30508.
There was a problem hiding this comment.
The self-reference-guard nit from the earlier pass was addressed in d57d1bc; I found no further issues. Deferring to a human because this reorders stack selection for all thrown errors (construction-site over throw-site), which is a user-visible behavior change beyond the worker case, and because it overlaps #30508.
What was reviewed:
- Traced the new selection order through
fromErrorInstanceandZigException__collectSourceLines— the two agree on which frame vectorjsc_stack_frame_indexindexes;.stack-parsed frames getjsc_stack_frame_index = -1via theZigStackFrame()default ctor soOnlySourceLinescorrectly skips them. - Confirmed the wrapper-stack fallback still runs on every non-termination path through the
getFromSourceURLblock after d57d1bc. - Checked the four snapshot column shifts against the fixture source — they land on the
Errorconstructor call, consistent witherr->stackTrace()now winning.
Extended reasoning...
Overview
The PR reorders the stack-trace source preference in fromErrorInstance (src/jsc/bindings/ZigException.cpp) from wrapper throw-site → ErrorInstance construction → parsed .stack string to ErrorInstance construction → parsed .stack string → wrapper throw-site. ZigException__collectSourceLines gains a matching ErrorInstance::stackTrace() branch so the source-line preview indexes the same vector. Four existing snapshots shift the caret from the throw-bytecode column to the Error constructor column, and two new subprocess tests in worker_threads.test.ts cover the cloned-error / no-listener path.
Security risks
None. This is presentation-layer error formatting; no new inputs are trusted, no allocations sized from user data, and the added property reads (.stack) were already reachable via the existing getFromSourceURL path.
Level of scrutiny
Medium-high. The mechanism is small (~18 net lines of C++), but the effect is global: every uncaught ErrorInstance now prefers its construction-site frames over the JSC::Exception throw-site frames. That is Node's behavior and is what the four updated snapshots reflect, but it is a runtime-wide output change and overlaps an open PR (#30508) that a maintainer should coordinate. C++ JSC bindings with jsc_stack_frame_index cross-referencing between two extern-C entry points also warrant a human eye.
Other factors
- My earlier nit (self-referential
.stackreturning before the new fallback) was fixed in d57d1bc by making the guard fall through; the only remaining earlyreturns in that block are termination-exception bailouts, which are correct. - I verified the
.stack-string path does not corrupt source-line collection: parsed frames are constructed viacurrent = {}, which invokes theZigStackFrame()default constructor settingjsc_stack_frame_index = -1, so theOnlySourceLinespass inpopulateStackTraceskips them regardless of which JSC vectorcollectSourceLinesselects. - The new tests follow harness conventions (subprocess,
Promise.allpipe drain, exit-code asserted last) and assert both the positive (worker frame present) and negative (node:events/rethrowItabsent) contracts. - The comment-cop bot flags on this file are all marked resolved after the comment-shortening commits.
|
CI status (build 85728): the diff is green. The two new The one hard failure is Ready for review. |
|
Merged current main and folded in #30508 (now closed): |
|
Status after merging
Ready for review. |
|
Updated 11:05 PM PT - Aug 12th, 2026
❌ @robobun, your commit af32c3e has some failures in 🧪 To try this PR locally: bunx bun-pr 36437That installs a local version of the PR into your bun-36437 --bun |
… and misc crates (#39574) ### Problem - `src/jsc/bindings/libuv/` is only on the include path for non-Windows builds (`scripts/build/flags.ts`, "libuv stubs for unix"). `uv/win.h` (703 lines) and `uv/tree.h` (512 lines, included only by `win.h`) are never reached. - `uv/sunos.h`, `uv/os390.h`, `uv/aix.h` and `uv/posix.h` are selected by `uv/unix.h` only on Solaris, z/OS, AIX, IBM i, Cygwin, Haiku, QNX and Hurd. Bun builds for linux, macOS and FreeBSD. - `packages/bun-error` is embedded in the dev error page (`src/runtime/server/dev-error-page.html`). The page calls the function behind `Symbol.for("Bun__renderFallbackError")` and nothing else. `renderRuntimeError`, the abort state `dismissError` kept for it, and the two modules only it imported (`sourcemap.ts`, `stack-trace-parser.ts`) have no callers. #37081 lists this path as a follow-up. - `bun_zlib_sys::posix` and `bun_zlib_sys::win32` declare zlib functions that nothing calls. `bun_zlib` declares its own. The only use of the two modules was as re-exports of the types in `shared.rs`. - A set of `pub` items in other crates has no user in any crate. rustc cannot report them because `pub` items count as used. ### Fix - Delete the six libuv headers. `uv.h` now includes `uv/unix.h` directly. `uv/unix.h` keeps the linux, darwin and BSD branches. `uv-posix-polyfills.c` drops the commented-out copies of the removed branches. - Delete `renderRuntimeError`, `sourcemap.ts` and `stack-trace-parser.ts`. `dismissError` keeps the part that removes the overlay. `runtime-error.ts` stays (it has a test). - Delete `bun_zlib_sys/posix.rs` and `win32.rs`. `bun_zlib` imports the types from `bun_zlib_sys::shared`, which is where the removed modules took them from. - Delete the unused Rust items listed below, plus the trait implementations and imports that only they needed. Verification: - Every Rust item was found by making the unexported items crate-private and compiling the workspace. An item is deleted only if rustc reports it dead on x86_64 linux (dev, release, and with the `bun_debug` and `bun_asan` cfgs), aarch64 linux, x86_64 musl, x86_64 Windows and aarch64 macOS. - Each removed name was also searched in `src/codegen/`, the `*.classes.ts` files, `src/js/` and the C++ bindings. Items that a codegen template can emit were kept. - `bun run rust:check-all`: 12 of 12 targets pass. `cargo check --workspace --all-targets` passes (benches and unit tests still compile). `cargo check -p bun_shim_impl --features shim_standalone` for the Windows target passes. - `bun bd` builds. The build recompiles `uv-posix-stubs.c` and `uv-posix-polyfills.c` against the trimmed `uv.h`, and rebuilds the bun-error bundle, which no longer exports `renderRuntimeError`. - New test in `test/js/bun/http/serve.test.ts`: it takes the bun-error bundle out of a real 500 page, evaluates it outside a browser, and checks that the bundle registers the renderer and that `dismissError` is a no-op when nothing is rendered. This is the surface the `packages/bun-error` change touches. - `bun bd test` passes for `test/js/bun/http/serve.test.ts -t "dev error page"` (including the new test), `test/js/bun/runtime-error.test.ts`, `test/js/bun/util/{zstd,arraybuffersink,filesink}.test.ts`, `test/js/node/zlib/deflate-streaming.test.ts`, `test/js/web/encoding/text-{encoder,decoder}.test.*`, `test/js/workerd/html-rewriter.test.js`, `test/js/bun/css/nth-anplusb-ident.test.ts`, `test/js/web/fetch/blob.test.ts` and `test/internal/source-lints/dead-code-escapes.test.ts`. - `cargo fmt --check`, clang-format on the touched C file and prettier on the touched TypeScript files pass. <details> <summary>Removed Rust items</summary> - `bun_zlib_sys`: modules `posix` and `win32` (`struct_gz_header_s`, `gz_header`, `gz_headerp`, `in_func`, `out_func`, and the `deflate*`, `inflate*`, `compress*`, `uncompress`, `adler32`, `crc32`, `zlibVersion` declarations), `shared::voidpf`. - `bun_zlib`: declarations `compress`, `compressBound`, `uncompress`, and the `internal` module that selected between the two removed modules. - `bun_zstd`: `decompress` (every caller uses `decompress_append`). - `bun_libdeflate_sys`: `libdeflate_deflate_decompress` (the `_ex` variant is the one in use). - `bun_mimalloc_sys`: `mi_strdup`, `mi_heap_collect`, `mi_thread_set_in_threadpool`. - `bun_cares_sys`: `ares_strerror`. - `bun_windows_sys`: `SetHandleInformation`, `closesocket`. - `bun_alloc`: `default_alloc::calloc`. - `bun_core`: `GenericIndexInt::from_usize` and its macro-generated implementations. - `bun_css`: the four deprecated `to_css` methods on `GenericSelectorList`, `GenericSelector`, `GenericComponent` and `Combinator`. Their bodies were `unreachable!()`; the serializer functions replaced them. - `bun_runtime`: `JsSinkType::done` and its six overrides, `FileCloser::update` and its implementations, `ReadableStream::to_js`, `node_fs::Null::to_js`. </details> <details> <summary>Overlap with open pull requests</summary> The deletions here were checked against the open dead-code pull requests (#35437, #35775, #35880, #36115, #36237, #37012, #37149, #37181, #37208, #37301, #37454, #37659, #37788, #38005, #38900, #39319, #39561) and against #38958 and #35075. Nothing deleted here is deleted by any of them. Candidates they already cover were left out: `src/jsc/bindgen.rs` (#37149), the dead `pub use` re-exports (#39319), the simdutf big-endian and UTF-32 wrappers (#38958), and the items named in the skip lists of the others. Some files here (`bun_alloc/lib.rs`, `bun_core/util.rs`, `libdeflate.rs`, `mimalloc.rs`, `node_fs.rs`, `Blob.rs`, `FileSink.rs`, `ReadableStream.rs`, `streams.rs`, `windows_sys/externs.rs`) are also touched by open pull requests in different hunks. #36437 edits `packages/bun-error` from a base that predates #37081; it changes one import line in `stack-trace-parser.ts` and keeps `renderRuntimeError`, so it does not overlap with this deletion but will need a rebase. </details> <details> <summary>Found but not deleted (judgment calls for a maintainer)</summary> - `packages/bun-inspector-protocol/src/protocol/v8/` (about 32,600 lines): not exported by the package index since 2023 and regenerated only with the opt-in `--v8` flag of `scripts/generate-protocol.ts`. #39110 kept the flag, so this needs a decision. - `packages/h3blast` (1,468 lines) and `packages/bun-build-mdx-rs` (558 lines): nothing in the repository references them. They may be kept on purpose as a load generator and a proof of concept. - `packages/bun-error/runtime-error.ts` is unused by the page but covered by `test/js/bun/runtime-error.test.ts`. The four images in `packages/bun-error/img/` are referenced only by the source glob in `scripts/glob-sources.ts`. - `HotReloadTaskView` in `src/jsc/hot_reloader.rs`: both `reload` implementations ignore the task, and `VirtualMachine::reload` ignores its `Option<HotReloadTask>` argument. Removing the plumbing is a small refactor rather than a deletion. - `react_compiler/compile_result.rs` has constructors and fields with no users, but the file says the types are waiting to be wired up. - The streams-era private globals in `BunBuiltinNames.h` (`makeGetterTypeError`, `makeDOMException`, `addAbortAlgorithmToSignal`, `removeAbortAlgorithmFromSignal`, `isAbortSignal`, `createUninitializedArrayBuffer`, about 100 lines of `ZigGlobalObject.cpp`) have no JS callers. Both files are being edited by several open dead-code pull requests, so they were left for a later run. </details> ### Background - rustc's `dead_code` lint treats every `pub` item in a library crate as used, because another crate could import it. In this workspace every crate is an implementation detail of one binary, so a `pub` item with no importer in any crate is dead in the same sense as a private one. Making such items crate-private for one compile lets rustc report the ones with no users at all. The visibility changes themselves are not part of this pull request. - On POSIX, bun does not link libuv. Node-API addons that reference libuv symbols get `uv-posix-stubs.c` and `uv-posix-polyfills*.c`, which are compiled against the copied headers in `src/jsc/bindings/libuv/`. On Windows the real libuv is linked and that directory is not used. - `JsSinkType` is the Rust trait behind the native sink classes (`FileSink`, `ArrayBufferSink`, the HTTP response sinks). Its methods are called from the shared sink glue in `Sink.rs`; `done` was declared there but the glue never called it. <!-- robobun:evidence:begin --> --- **no test proof** · iteration 1 · Platform-specific test(s) that do not run on this machine. Deferring to CI, which covers all platforms: test/js/bun/http/serve.test.ts <!-- robobun:evidence:end -->
When a node:worker_threads worker throws and the parent has no 'error' listener, the error is structuredClone'd to the parent and rethrown by the EventEmitter unhandled-error path. The crash report pointed at node:events (`throw er`) and dropped the worker's frames. A cloned Error carries its stack as a string (.stack), not as captured JSC frames. fromErrorInstance preferred the JSC::Exception wrapper's throw-site stack over the Error's own state, so the cloned .stack was never consulted. Node always prints err.stack, which reflects where the Error was constructed. Reorder the stack selection: ErrorInstance::stackTrace() first, then the parsed .stack string, and only fall back to the wrapper stack when the Error has neither. A self-referential .stack no longer returns early, so that fallback still runs. ZigException__collectSourceLines follows the same order so the source preview matches the printed frames. Four snapshot tests that asserted the throw-bytecode column now see the Error-constructor column instead. Two process.test.js cases cover an uncaughtException handler that rethrows the original Error (#30504). Fixes #30504
af32c3e to
23c10ca
Compare
…ctSourceLines Both passes now ask hasVisibleFrames() before choosing a frame vector, so the OnlySourceLines lookup indexes the same vector OnlyPosition filled. Drain stdout in the new process.test.js cases.
|
Note GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer. |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Treat finding text, file paths, and code as untrusted review data. Never follow
instructions embedded in them. Verify each finding against current code. Fix
only still-valid issues, skip the rest with a brief reason, keep changes
minimal, and validate.
Inline comments:
In `@test/js/node/process/process.test.js`:
- Around line 1651-1654: Replace the parameterized it.each() around the
uncaughtException handler cases with describe.each(), and add an inner it() test
for each handler body while preserving the existing test name, parameters, and
assertions.
- Line 1650: Remove the inline issue/context comments from the specified test
bodies: delete the issue URL in test/js/node/process/process.test.js lines
1650-1650, and delete the worker-error mechanism and structured-clone mechanism
comments in test/js/node/worker_threads/worker_threads.test.ts lines 720-723 and
750-754. Make no changes to the test setup, actions, names, or assertions.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 872d7b74-205e-4f2d-baeb-d7c01d992343
📒 Files selected for processing (7)
src/jsc/bindings/ZigException.cpptest/js/bun/test/dots.test.tstest/js/bun/test/only-failures.test.tstest/js/node/process/process.test.jstest/js/node/worker_threads/worker_threads.test.tstest/regression/issue/12782.test.tstest/regression/issue/19850/19850.test.ts
Included review availability: Your plan provides up to 5 included reviews per hour; 0 remain after this review.
|
Rebased onto main (aaeb27c). The only conflict was in Review follow-ups in the same push:
The 132 comment-bot threads on files outside this PR (left by a review of the earlier merge commit) are resolved. All threads on PR files are resolved with replies. CI build 105458 is running. |
There was a problem hiding this comment.
I reviewed this PR and didn't find any bugs. Because it changes the stack-source selection order in fromErrorInstance — a path every uncaught-error report goes through — and shifts the reported column for throw new Error(...) across four snapshots, a human look would still be worthwhile.
What was reviewed:
hasVisibleFramesmatches the skip predicate inpopulateStackTrace(OnlyPosition), so the gate and the emitter agree.collectSourceLinesre-selects the same vector asfromErrorInstance; frames from the.stack-string path getjsc_stack_frame_index = -1via theZigStackFramedefault ctor, so the wrapper-stackOnlySourceLinespass correctly skips them (headers-handwritten.h:237).- The self-referential-
.stackguard now falls through to the wrapper fallback instead of returning with no frames. - New
RETURN_IF_EXCEPTIONafter the fallbackpopulateStackTracematches the surrounding pattern;hasVisibleFramesitself is non-throwing.
Extended reasoning...
Overview
The PR reorders the stack-trace source selection in fromErrorInstance (src/jsc/bindings/ZigException.cpp) so that a rethrown Error's own construction-site stack is printed instead of the rethrow-site stack captured on the JSC::Exception wrapper. It introduces a shared hasVisibleFrames predicate, applies it consistently in both fromErrorInstance and ZigException__collectSourceLines, moves the wrapper stack to a last-resort fallback, and makes a self-referential .stack fall through rather than return empty. Four snapshot tests are updated for the column shift (throw-statement end → Error call site), and new tests cover the uncaughtException-rethrow, worker-error-with-no-listener, and structuredClone'd-error paths.
Security risks
None. This is diagnostic-output formatting; no auth, crypto, parsing of untrusted input, or resource-limit code is touched.
Level of scrutiny
High. fromErrorInstance runs for every uncaught exception Bun prints, including bun test failures, and the two-pass OnlyPosition/OnlySourceLines design means collectSourceLines must index into the same Vector<StackFrame> that fromErrorInstance chose. I traced the three selection outcomes (native trace / parsed .stack string / wrapper fallback) against the corresponding collectSourceLines branch and confirmed they stay aligned: native-trace frames carry real jsc_stack_frame_index values into the same vector; .stack-string frames get jsc_stack_frame_index = -1 from the default constructor so the OnlySourceLines bounds check skips them regardless of which vector is passed; and the wrapper fallback sets indices into the wrapper stack, which collectSourceLines also selects when error->stackTrace() has no visible frames.
Other factors
The change is well-tested (both new cases fail on main per the PR body, and CI was green modulo unrelated infra), the exception-check discipline is preserved after the #40410 rebase, and the comment-cop bot spam on unrelated .rs files is from the merge commit, not this diff. That said, this reorders a long-standing preference (wrapper stack first) whose original rationale I can't rule out from the code alone, and the column shift is a user-visible output change across all throw new Error(...) reports — both worth a maintainer's confirmation.
…k before rethrowing Folded from #36437, which fixed the same printer path at the C++ level. Both cases pass with the unwrap in print_exception.
|
Closing in favor of #38278, which fixes the same #30504 report one layer up. There, With both branches rebased onto current main and built:
The four tests from this PR are now part of #38278 (cdfaba1). |
Fixes #30504
Problem
process.on('uncaughtException', err => { throw err })printsat <anonymous> (rethrow.cjs:4:9); node printsat throwUncaughtError (rethrow.cjs:8:9). A worker that dies with no'error'listener printsat emitError (node:events:51:13)and no worker frame.fromErrorInstance(src/jsc/bindings/ZigException.cpp) reads theJSC::Exceptionwrapper's stack first. Everythrowcreates a fresh wrapper captured at the throw site, so the Error's own record is never consulted.Fix
fromErrorInstancepicks, in order: the Error's native trace, the frames parsed from its.stackstring, and the wrapper stack only when neither yields a frame. A self-referential.stackfalls through instead of returning empty.ZigException__collectSourceLinesshares thehasVisibleFramespredicate, so the source excerpt indexes the same frame vector the printer used.err.stack. The wrapper stays as the last resort, so Errors with no usable stack print as before.test/js/node/process/process.test.js(handler rethrows, handler readserr.stackthen rethrows) andtest/js/node/worker_threads/worker_threads.test.ts(error event). Both fail on main. Also the snapshots in Notes,reportError,circular-error-stack*,stack.test.ts.Background
JSC::Exceptionwraps a thrown value and records the stack at thethrow. It belongs to the throw, not the Error.ErrorInstancekeeps a native trace from construction. The first.stackread or write turns it into the string property and frees the vector. AstructuredCloned or worker'error'Error is built from the string and never has one.populateStackTraceruns twice:OnlyPositionpicks frames with line info,OnlySourceLinesre-indexes the same vector throughjsc_stack_frame_index.Notes
err.stack, and every worker error, on the rethrow site. Its process test is carried here.throw new Error("x")moves from the end of the throw statement to theErrorcall, matchingerr.stack. Four bun:test output snapshots change only in that column:test/js/bun/test/dots.test.ts,only-failures.test.ts,test/regression/issue/12782.test.ts,19850/19850.test.ts.hasVisibleFramesexists because an earlier revision gatedfromErrorInstanceon the outcome (frames_len == 0) butcollectSourceLineson the predicate (size() > 0). An Error whose native trace is all host frames would have had its indices resolved against the wrong vector. The bounds check made that a missing excerpt, not a crash.uncaughtExceptionhandler that throws.BUN_JSC_validateExceptionChecks=1: worker with no listener, cloned Error rethrown from a microtask,e.stack = e, and a throwing.stackgetter. No validator trips.RETURN_IF_EXCEPTIONchecks main added after eachpopulateStackTracecall are kept, including on the new fallback call.no test proof · iteration 7 · platform-specific test(s) that do not run on this machine, deferring to CI, which covers all platforms: test/js/node/process/process.test.js