Conversation
Install the host promise rejection tracker in the qjs CLI so rejections that still have no handler when the job queue drains print "Possibly unhandled promise rejection: <reason>" to stderr (via the JS_PrintValue path, so Error reasons keep their attached stack) and the process exits 1, matching js_std_promise_rejection_tracker and js_std_promise_rejection_check in quickjs-libc.c. A handler attached before or during the drain removes the entry. Add --no-unhandled-rejection (default still reports) and keep draining after a job JavaScript exception as js_std_loop does. Ported to the workspace layout: src/main.rs -> apps/cli/src/main.rs, imports via quickjs_oxide::engine::api, and the PendingJobOutcome/ into_error job API. Co-Authored-By: Claude Code <noreply@anthropic.com>
Add 12 byte-exact golden/differential cases covering Error and primitive reasons, stack frames, FIFO report order, pre- and mid-drain handling, derived/nested/rethrown rejections, plus --no-unhandled-rejection and the modules-20 case where an handled import() still reports the inner module evaluation rejection. Differential assertions run against QJS_ORACLE. Ported to the workspace layout: the CLI integration target now lives at apps/cli/tests/cli.rs with submodules under tests/cli/, so the cases are in tests/cli/rejections.rs and reuse the shared run_cli/ModuleFixture helpers via `super::*`. Co-Authored-By: Claude Code <noreply@anthropic.com>
lfkdsk
force-pushed
the
pr/host-unhandled-rejection
branch
from
September 17, 2026 21:27
def0e14 to
c296ec4
Compare
lfkdsk
added a commit
to lfkdsk/quickjs-oxide
that referenced
this pull request
Sep 18, 2026
Old-to-new path mapping (src/main.rs -> apps/cli/src/main.rs; tests/cli.rs -> apps/cli/tests/cli.rs + tests/cli/rejections.rs), mechanical adaptations (engine::api imports, PendingJobOutcome/ into_error job API, profiling session), all gate outputs, and the 12 byte-exact pinned-oracle differential results. Co-Authored-By: Claude Code <noreply@anthropic.com>
lfkdsk
added a commit
to lfkdsk/quickjs-oxide
that referenced
this pull request
Sep 18, 2026
… and thenable Close the two byte-level mismatches the cross-family review of pocket-stack#24 found in the `Possibly unhandled promise rejection:` line, making the differential surface 66/66 byte-exact with pinned QuickJS 2026-06-04. 1. Failed dynamic import no longer doubles the message. Upstream's host js_module_loader throws the final ReferenceError itself ("could not load module filename '%s'", quickjs-libc.c:699), so the engine wrapper is never reached. The CLI file loader now raises a true realm-intrinsic JS ReferenceError via ModuleLoaderError::exception instead of a Message error the engine re-wrapped. Add public Context::new_native_error so an embedder can build intrinsic (global tamper-immune) native errors. 2. A throwing `then` getter no longer prints an extra `at <anonymous> (native)` frame. QuickJS invokes the PROMISE_RESOLVE/REJECT_FUNCTION class call handlers without pushing a JSStackFrame; mark the PromiseResolving native frame backtrace_hidden (same mechanism as the Iterator.next raw fast path) so the frame is kept for realm/budget accounting but omitted from backtraces. Add both probes to apps/cli/tests/cli/rejections.rs (golden + oracle differential), plus a module-file case covering the unhandled and caught channels. Verified by mutation tests and a 396-variant test262 Promise/resolve + dynamic-import/catch subset whose outcome set is identical before/after (74 pass, no regressions). Co-Authored-By: Claude Code <noreply@anthropic.com>
… and thenable Close the two byte-level mismatches the cross-family review of pocket-stack#24 found in the `Possibly unhandled promise rejection:` line, making the differential surface 66/66 byte-exact with pinned QuickJS 2026-06-04. 1. Failed dynamic import no longer doubles the message. Upstream's host js_module_loader throws the final ReferenceError itself ("could not load module filename '%s'", quickjs-libc.c:699), so the engine wrapper is never reached. The CLI file loader now raises a true realm-intrinsic JS ReferenceError via ModuleLoaderError::exception instead of a Message error the engine re-wrapped. Add public Context::new_native_error so an embedder can build intrinsic (global tamper-immune) native errors. 2. A throwing `then` getter no longer prints an extra `at <anonymous> (native)` frame. QuickJS invokes the PROMISE_RESOLVE/REJECT_FUNCTION class call handlers without pushing a JSStackFrame; mark the PromiseResolving native frame backtrace_hidden (same mechanism as the Iterator.next raw fast path) so the frame is kept for realm/budget accounting but omitted from backtraces. Add both probes to apps/cli/tests/cli/rejections.rs (golden + oracle differential), plus a module-file case covering the unhandled and caught channels. Verified by mutation tests and a 396-variant test262 Promise/resolve + dynamic-import/catch subset whose outcome set is identical before/after (74 pass, no regressions). Co-Authored-By: Claude Code <noreply@anthropic.com>
lfkdsk
force-pushed
the
pr/host-unhandled-rejection
branch
from
September 18, 2026 19:03
6a1e4e6 to
275bb67
Compare
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.
What
The
qjsCLI now installs the host promise-rejection tracker the wayquickjs-libc.cdoes (js_std_promise_rejection_tracker/js_std_promise_rejection_check): a rejection that still has no handler when the job queue drains printsPossibly unhandled promise rejection: <reason>to stderr through theJS_PrintValuepath (Error reasons keep their stack) and the process exits 1. A handler attached before or during the drain removes the entry.--no-unhandled-rejectionis added with the same default as pinnedqjs, and draining continues after a job throws, matchingjs_std_loop.Previously these rejections were silent and the process exited 0.
Verification
--no-unhandled-rejection, and the modules case where a handledimport()still reports the inner module evaluation rejection.cargo test --locked --workspace --all-targets: 2846 pass / 0 fail;check-rust-only.shandcargo fmt --checkgreen.Part of the parity work tracked from the
docs/parity.mdhost-library row; no Test262 receipts touched.