Skip to content

fix(core): isolate afterVerify and afterSettle hook errors from payment outcomes#1892

Open
skyc1e wants to merge 1 commit intox402-foundation:mainfrom
skyc1e:fix/hook-error-isolation
Open

fix(core): isolate afterVerify and afterSettle hook errors from payment outcomes#1892
skyc1e wants to merge 1 commit intox402-foundation:mainfrom
skyc1e:fix/hook-error-isolation

Conversation

@skyc1e
Copy link
Copy Markdown

@skyc1e skyc1e commented Apr 1, 2026

Summary

Fixes #1826.

Lifecycle hooks (afterVerify, afterSettle) ran inside the main try block in both x402ResourceServer and x402Facilitator. If a hook threw, the error fell into the onVerifyFailure / onSettleFailure catch path, incorrectly treating a successful payment as a failure.

Root cause

// Before: hook error falls into the catch block
for (const hook of this.afterVerifyHooks) {
  await hook(resultContext); // throws → caught as verify failure
}

Fix

Wrap each hook invocation in its own try/catch and log the error so hook side-effects (logging, metrics, notifications) cannot corrupt payment state:

for (const hook of this.afterVerifyHooks) {
  try {
    await hook(resultContext);
  } catch (hookError) {
    console.error("afterVerify hook threw an error (payment succeeded):", hookError);
  }
}

Files changed

  • packages/core/src/server/x402ResourceServer.tsafterVerify and afterSettle hook isolation
  • packages/core/src/facilitator/x402Facilitator.ts — same fix for facilitator hooks

Tests added

  • Hook throws → verify/settle result is still returned as success
  • Second hook still executes after first throws
  • Settlement hook throws → settlement result still returned as success

All 97 existing tests continue to pass.

…nt outcomes

Lifecycle hooks (afterVerify, afterSettle) ran inside the main try block
in both x402ResourceServer and x402Facilitator. If a hook threw, the error
fell into the onVerifyFailure / onSettleFailure catch path, incorrectly
treating a successful payment as a failure.

Wrap each hook invocation in its own try/catch and log the error so hook
side-effects (logging, metrics, notifications) cannot corrupt payment state.

Closes coinbase#1826
@cb-heimdall
Copy link
Copy Markdown

🟡 Heimdall Review Status

Requirement Status More Info
Reviews 🟡 0/1
Denominator calculation
Show calculation
1 if user is bot 0
1 if user is external 0
2 if repo is sensitive 0
From .codeflow.yml 1
Additional review requirements
Show calculation
Max 0
0
From CODEOWNERS 0
Global minimum 0
Max 1
1
1 if commit is unverified 0
Sum 1

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 1, 2026

@skyc1e is attempting to deploy a commit to the Coinbase Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions bot added typescript sdk Changes to core v2 packages labels Apr 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

sdk Changes to core v2 packages typescript

Projects

None yet

Development

Successfully merging this pull request may close these issues.

afterVerify and afterSettle hooks lack error isolation, throwing hook breaks payment response

2 participants