- From: Marcos Cáceres <notifications@github.com>
- Date: Mon, 02 Mar 2026 19:01:40 -0800
- To: w3c/payment-request <payment-request@noreply.github.com>
- Cc: Subscribed <subscribed@noreply.github.com>
- Message-ID: <w3c/payment-request/issues/1057@github.com>
marcoscaceres created an issue (w3c/payment-request#1057) As identified in #1040, the spec has an over reliance on AbortError... The Payment Request specification uses `AbortError` inconsistently across different failure scenarios, conflating: - User-initiated cancellation - Developer errors (API misuse) - Security/policy violations - System/infrastructure failures This makes it impossible for merchants to programmatically distinguish between these fundamentally different error categories. --- ## Error Categories (Web Platform Conventions) | Category | Appropriate Exception | Semantics | |----------|----------------------|-----------| | **Developer error** | `InvalidStateError`, `NotAllowedError` | API called incorrectly; caller's fault | | **User action** | `AbortError` | User explicitly cancelled | | **Security/policy** | `SecurityError`, `NotAllowedError` | Permission denied, policy violation | | **System/infra** | `OperationError` | External system failure (handler crash, OS kill) | --- ## Problematic Cases in `show()` ### 1. Document Not Visible **Location:** [`show()` method, step 6](index.html:1049) **Current behavior:** ``` If document's visibility state is not "visible", return a promise rejected with an "AbortError" DOMException. ``` **Problem:** This is a **developer error** — the page called `show()` while not visible (e.g., background tab). The user didn't abort anything. **Should be:** `NotAllowedError` --- ### 2. Payment Request Already Showing **Location:** [`show()` method, step 8](index.html:1067) **Current behavior:** ``` If the user agent's payment request is showing boolean is true, then: - Set request.[[state]] to "closed" - Return a promise rejected with an "AbortError" DOMException. ``` **Problem:** This is a **developer error** — calling `show()` when a payment UI is already visible. The user didn't abort anything. **Should be:** `InvalidStateError` **Rationale:** - This is classic "object in invalid state" per WebIDL - Similar to calling `start()` on an already-started operation - Consistent with step 7 which uses `InvalidStateError` for wrong `[[state]]` --- ### 3. UA Immediate Abort (Private Browsing) **Location:** [`show()` method, step 12](index.html:1086) **Current behavior:** ``` Optionally: - Reject acceptPromise with an "AbortError" DOMException. - [Note: allows UA to act as if user immediately aborted] ``` **Problem:** This conflates UA policy decisions with user cancellation. In private browsing mode, the *user agent* is refusing, not the *user*. **Should be:** `NotAllowedError` **Rationale:** - Private browsing = UA policy to protect privacy = `NotAllowedError` --- ### 4. detailsPromise Rejection **Location:** [Update algorithm](index.html:3985) **Current behavior:** ``` Upon rejection of detailsPromise: - Abort the update with request and an "AbortError" DOMException. ``` **Problem:** If the merchant's `detailsPromise` rejects, that's a **developer error** (their server failed, their code threw). Using `AbortError` implies the user cancelled. **Should be:** Pass through the original rejection reason, or use `OperationError` **Rationale:** - The merchant's own promise failed; that's not "abort". - Original exception provides better debugging --- ## Problematic Cases in `retry()` ### 5. Document Becomes Inactive During Retry **Location:** [`retry()` method](index.html:2589) **Current behavior:** ``` If document stops being fully active while the user interface is being shown: - Close down the user interface - [No explicit rejection specified, but likely AbortError] ``` **Problem:** Document deactivation during retry is an infrastructure failure, not user cancellation. **Should be:** `InvalidStateError` --- ## Proposed Fix Summary | Case | Current | Proposed | Priority | |------|---------|----------|----------| | Document not visible | `AbortError` | `InvalidStateError` | High | | Already showing | `AbortError` | `InvalidStateError` | High | | Private browsing abort | `AbortError` | `NotAllowedError` | Medium | | detailsPromise rejects | `AbortError` | Original error / `OperationError` | High | | Payment handler error | `AbortError` | `OperationError` | High | --- ## Backwards Compatibility Changing error types is technically breaking, but: 1. Most merchants catch all errors from `show()` generically 2. Those parsing error messages are already dealing with inconsistency 3. Semantic correctness enables better error handling going forward 4. Can be staged: update spec, then implementations, with clear release notes -- Reply to this email directly or view it on GitHub: https://github.com/w3c/payment-request/issues/1057 You are receiving this because you are subscribed to this thread. Message ID: <w3c/payment-request/issues/1057@github.com>
Received on Tuesday, 3 March 2026 03:01:44 UTC