Skip to content

Allow payment handlers to report back errors via Payment Request API#1050

Merged
marcoscaceres merged 5 commits intogh-pagesfrom
smcgruer-add-payment-handler-error-case
Mar 3, 2026
Merged

Allow payment handlers to report back errors via Payment Request API#1050
marcoscaceres merged 5 commits intogh-pagesfrom
smcgruer-add-payment-handler-error-case

Conversation

@stephenmcgruer
Copy link
Collaborator

@stephenmcgruer stephenmcgruer commented Nov 13, 2025

See #1040

Co-authored by: @marcoscaceres

The following tasks have been completed:

  • Modified Web platform tests (link) - not possible to test, as a test cannot make an app throw an internal error. We could potentially test this via web-based payment handlers, but those tests would only work in Chromium and not WebKit (as it doesn't ship web-based payment handlers). Otherwise we could define some sort of WebDriver API to install a fake payment app, similar to how WebAuthn works?

Implementation commitment:

  • WebKit
  • Chromium
  • Gecko (link to issue) - N/A, don't ship Payment Request

Optional, impact on Payment Handler spec?
w3c/web-based-payment-handler#428


Preview | Diff

@stephenmcgruer stephenmcgruer force-pushed the smcgruer-add-payment-handler-error-case branch from ccb85c9 to aaa261e Compare January 30, 2026 17:38
Copy link
Collaborator Author

@stephenmcgruer stephenmcgruer left a comment

Choose a reason for hiding this comment

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

Ok I've incorporated your comments (thanks!) and put together three variants:

  1. A version where we take the unspecified error from the platform handler, and use the "let |error| be an appropriate {{DOMException}}" wording -e9eec11
  2. A version where the payment handler is presumed to pass us a DOMException directly (i.e., any conversion to DOMException happens 'inside' the relevant payment handler and any spec it has) - ae1280b
  3. A version which uses a general JavaScript value like AbortSignal does, and rejects with that reason - d976730

I personally prefer (2), but I'm open to any of them.

@marcoscaceres marcoscaceres force-pushed the smcgruer-add-payment-handler-error-case branch from d976730 to 236c39b Compare March 2, 2026 11:12
@marcoscaceres
Copy link
Member

Alternative, building on @stephenmcgruer proposal:
236c39b

PayPal's SDK exposes onError and onCancel callbacks to merchants. Currently, the Payment Request API returns AbortError for both user cancellation AND payment handler errors, forcing PayPal to parse error.message strings that vary by browser version.

Proposed Solution

Use the existing WebIDL OperationError DOMException type to distinguish payment handler errors from user cancellation (AbortError).

Two OperationError Cases

Case 1: OS-Level Error

When the operating system kills the payment UI (e.g., memory pressure when user switches apps):

User opens payment sheet → Switches to another app → 
OS kills payment UI for memory → OperationError

This is not user cancellation - the user didn't intentionally close the sheet.

Case 2: Payment Handler Internal Error

When the payment handler encounters an error during processing:

User selects PayPal → PayPal server returns 500 → 
PayPal handler signals error → OperationError

This is not user cancellation - the payment failed due to a technical issue.

Backwards Compatibility

Self-healing approach:

  1. PayPal continues using message-based detection for old browsers
  2. New browsers will throw OperationError instead of AbortError
  3. PayPal can add error.name === "OperationError" check
  4. Code naturally works in both old and new browsers:
function handlePaymentError(error) {
  // New path: check error type first
  if (error.name === "OperationError") {
    this.onError(error);
    return;
  }
  
  // Legacy path: message-based detection for old browsers
  if (error.name === "AbortError") {
    const cancelMessages = [
      "Request cancelled",
      "User closed the Payment Request UI."
    ];
    if (cancelMessages.some(m => error.message?.includes(m))) {
      this.onCancel();
    } else {
      this.onError(error);
    }
  }
}

@marcoscaceres marcoscaceres marked this pull request as ready for review March 2, 2026 21:36
@stephenmcgruer stephenmcgruer removed the request for review from rsolomakhin March 2, 2026 22:12
@stephenmcgruer
Copy link
Collaborator Author

(Removing Rouslan for review as he is no longer working on Payment Request :))

@marcoscaceres
Copy link
Member

I don't think this is testable... but we should file browser bugs and I need to check if WebKit is currently bailing out anywhere with UnknownError instead of OperationError.

@marcoscaceres
Copy link
Member

We should get an Ok from the folks in #1040 before merging, in case we've missed something... but otherwise, this seems ok to me.

@stephenmcgruer
Copy link
Collaborator Author

Filed bugs for Chromium and WebKit, filed an issue for Web-Based Payment Handler API, and added the following for WPT impact:

We could potentially test this via web-based payment handlers, but those tests would only work in Chromium and not WebKit (as it doesn't ship web-based payment handlers). Otherwise we could define some sort of WebDriver API to install a fake payment app, similar to how WebAuthn works?

@stephenmcgruer
Copy link
Collaborator Author

We should get an Ok from the folks in #1040 before merging, in case we've missed something... but otherwise, this seems ok to me.

Looks like we have that ok - @ianbjacobs any concerns/thoughts from your side, or are we good to land this?

Copy link
Collaborator

@ianbjacobs ianbjacobs left a comment

Choose a reason for hiding this comment

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

I defer to the implementers here; and you seem happy so I'm happy.

@marcoscaceres marcoscaceres merged commit 21370b1 into gh-pages Mar 3, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants