镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

Reject a Rust method's returned promise with what it throws - #8255

Merged
bartlomieju merged 2 commits into
mainfrom
biwanczuk/rust-jsg-capture-async-throws
Nov 6, 2026
Merged

bartlomieju merged 2 commits into
mainfrom
biwanczuk/rust-jsg-capture-async-throws

Conversation

@bartlomieju

@bartlomieju bartlomieju commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Under capture_async_api_throws, C++ JSG returns a rejected promise from
a method, property or call handler whose result is a promise, instead
of throwing (LiftKj_<v8::Localv8::Promise> in jsg/util.h). Argument
conversion errors and errors from the method itself are both caught; a
termination keeps propagating. Rust JSG threw them all synchronously,
so a Rust port of such a method behaved differently from the C++ one
it replaces, for example for ctx.restore(42).catch(...).

The generated callback of a #[jsg_method], #[jsg_property] getter or
#[jsg_callable] that returns a jsg::Promise or a v8::Localv8::Promise,
alone or in a Result, now runs its body through
jsg::capture_throws_as_rejection(). If the isolate captures throws as
rejections, the body runs in Lock::try_catch(), and what it throws is
returned as a rejected promise. Isolate::captures_throws_as_rejections()
reads the flag as C++ JSG does (jsg::getCaptureThrowsAsRejections()),
and Isolate::has_pending_exception() tells the helper that the body
threw. The jsg-macros README documents the behavior.

The new promise tests cover each way a callback fails, with the flag
on and off, a method that returns no promise, and a termination.
Without the macro change, the test with the flag on fails.

Compatibility: no compatibility flag. No Rust API that returns a
promise is exposed to Workers yet; this makes those to come match the
C++ ones under the existing capture_async_api_throws flag.

Under capture_async_api_throws, C++ JSG returns a rejected promise from
a method, property or call handler whose result is a promise, instead
of throwing (LiftKj_<v8::Local<v8::Promise>> in jsg/util.h). Argument
conversion errors and errors from the method itself are both caught; a
termination keeps propagating. Rust JSG threw them all synchronously,
so a Rust port of such a method behaved differently from the C++ one
it replaces, for example for `api.method(badArg).catch(...)`.

The generated callback of a #[jsg_method], #[jsg_property] getter or
#[jsg_callable] that returns a jsg::Promise or a v8::Local<v8::Promise>,
alone or in a Result, now runs its body through
jsg::capture_throws_as_rejection(). If the isolate captures throws as
rejections, the body runs in Lock::try_catch(), and what it throws is
returned as a rejected promise. Isolate::captures_throws_as_rejections()
reads the flag as C++ JSG does (jsg::getCaptureThrowsAsRejections()),
and Isolate::has_pending_exception() tells the helper that the body
threw.

The new promise tests cover each way a callback fails, with the flag
on and off, a method that returns no promise, and a termination.

Compatibility: no compatibility flag. No Rust API that returns a
promise is exposed to Workers yet; this makes those to come match the
C++ ones under the existing capture_async_api_throws flag.
@bartlomieju
bartlomieju requested review from a team as code owners November 6, 2026 11:01

@clanky-the-clanker clanky-the-clanker Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superseded by the review of 2ae33ceb.

This review, of 9c03481f

✅ Approved — No findings. With the flag on, a promise-returning Rust callback now rejects its promise with what it throws, as C++ JSG does. Terminations still propagate, and nothing changes with the flag off.

The decision is advisory: this review is a comment and never approves, blocks or requests changes on the pull request.


✅ All checks passed

🔒 Security: ✅ LGTM

No security concerns.


📖 AGENTS.md: ✅ LGTM

No AGENTS.md concerns.


📋 Code Quality: ✅ LGTM

No problems found.

  • A termination is thrown again and keeps propagating.
  • The rejected promise is created only after the TryCatch has gone out of scope.
  • The generated callbacks' early returns behave the same as before.
  • Tests cover the flag-on, flag-off and termination paths.

⚡ Performance: ✅ LGTM

The added work is one flag read per call, and only on methods that return a promise. try_catch runs only when the flag is on.


📝 Documentation: ✅ LGTM

The new README bullet correctly describes how promise-returning callbacks behave under capture_async_api_throws. It also narrows the general statement just above it that a Result error throws.


Reviewed commit: 9c03481f

@clanky-the-clanker clanky-the-clanker Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Approved — No findings. With the flag on, a promise-returning Rust callback now rejects its promise with what it throws, as C++ JSG does. Terminations still propagate, and nothing changes with the flag off.

The decision is advisory: this review is a comment and never approves, blocks or requests changes on the pull request.


✅ All checks passed

🔒 Security: ✅ LGTM

No security concerns.


📖 AGENTS.md: ✅ LGTM

No AGENTS.md concerns.


📋 Code Quality: ✅ LGTM

No problems found.

  • A termination is thrown again and keeps propagating.
  • The rejected promise is created only after the TryCatch has gone out of scope.
  • The generated callbacks' early returns behave the same as before.
  • Tests cover the flag-on, flag-off and termination paths.

⚡ Performance: ✅ LGTM

The added work is one flag read per call, and only on methods that return a promise. try_catch runs only when the flag is on.


📝 Documentation: ✅ LGTM

The new README bullet correctly describes how promise-returning callbacks behave under capture_async_api_throws. It also narrows the general statement just above it that a Result error throws.


Reviewed commit: 2ae33ceb — same changes as 9c03481f, so this is that commit's review (no new review was run; line numbers are as of 9c03481f)

@bartlomieju
bartlomieju merged commit db45d26 into main Nov 6, 2026
23 of 25 checks passed
@bartlomieju
bartlomieju deleted the biwanczuk/rust-jsg-capture-async-throws branch November 6, 2026 20:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants