Client Path
Lesson 7 of 8
15 min

Debugging x402 Clients

Learning Objectives

  • Inspect 402 responses and payment requirements
  • Identify common error messages
  • Use lifecycle hooks for debugging
  • Verify wallet configuration

Common Errors

When building x402 clients, you'll encounter these errors:

| Error | Meaning | Solution |
|-------|---------|----------|
| "No scheme registered for network X" | Client doesn't support the required network | Register the scheme with `registerExactEvmScheme` or `registerExactSvmScheme` |
| "Payment already attempted" | Payment was rejected and client won't retry | Check why payment failed, create new request |
| "Invalid signature" | Payment signature doesn't match | Check private key format (must have 0x prefix) |
| "Insufficient funds" | Wallet has no USDC | Add USDC to wallet |
| "Facilitator unreachable" | Can't connect to facilitator | Check network connection, try different facilitator |

Debugging with Hooks

Add verbose logging to see exactly what's happening:

typescript
const client = new x402Client()
  .onBeforePaymentCreation(async (ctx) => {
    console.log('🔵 [BEFORE] Creating payment');
    console.log('  Network:', ctx.selectedRequirements.network);
    console.log('  Amount:', ctx.selectedRequirements.amount);
    console.log('  PayTo:', ctx.selectedRequirements.payTo);
    console.log('  Facilitator:', ctx.selectedRequirements.facilitator);
    return undefined;
  })
  .onAfterPaymentCreation(async (ctx) => {
    console.log('✅ [SUCCESS] Payment created');
    console.log('  Signature:', ctx.paymentPayload.signature?.slice(0, 20) + '...');
    return undefined;
  })
  .onPaymentCreationFailure(async (ctx) => {
    console.error('❌ [FAILURE] Payment creation failed');
    console.error('  Error:', ctx.error.message);
    console.error('  Stack:', ctx.error.stack);
    return undefined;
  });

Inspecting 402 Responses

When you receive a 402, inspect what the server is asking for:

typescript
// Make request manually to see 402
const response = await fetch('https://api.example.com/protected');

if (response.status === 402) {
  const paymentHeader = response.headers.get('PAYMENT-REQUIRED');
  const decoded = JSON.parse(atob(paymentHeader));

  console.log('Server requires payment:', decoded);
  // Shows: network, scheme, amount, payTo, facilitator

  // Check if you support this network
  console.log('Network:', decoded.accepts[0].network);
  // Example: "eip155:8453" (Base)
}
If you see "No scheme registered", the network in the 402 response doesn't match what you registered!

Verifying Wallet Setup

Common wallet issues:

typescript
import { privateKeyToAccount } from "viem/accounts";

// ❌ WRONG - No 0x prefix
const key = '1234567890abcdef...';

// ❌ WRONG - Wrong length (must be 64 hex chars + 0x)
const key = '0x1234' as `0x${string}`;

// ✅ CORRECT
const key = '0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef' as `0x${string}`;

const signer = privateKeyToAccount(key);

// Verify it works
console.log('Wallet address:', signer.address);
// Should print: 0x...
Always verify your signer was created successfully by logging signer.address. If this throws an error, your private key format is wrong.

Knowledge Check

You get "No scheme registered for network eip155:8453". What's wrong?