Error Handling
Comprehensive guide to error handling in Shade402.
Error Classes
Shade402 defines specific error types for different scenarios:
X402Error
Base error class for all X402 errors:
class X402Error extends Error {
code: string;
details: ErrorDetails;
message: string;
}PaymentRequiredError
Thrown when payment is required:
class PaymentRequiredError extends X402Error {
paymentRequest: any;
code: 'PAYMENT_REQUIRED';
}PaymentExpiredError
Thrown when payment request has expired:
class PaymentExpiredError extends X402Error {
paymentRequest: any;
code: 'PAYMENT_EXPIRED';
}InsufficientFundsError
Thrown when wallet has insufficient balance:
class InsufficientFundsError extends X402Error {
requiredAmount: string;
availableAmount: string;
code: 'INSUFFICIENT_FUNDS';
}PaymentVerificationError
Thrown when payment verification fails:
class PaymentVerificationError extends X402Error {
code: 'PAYMENT_VERIFICATION_FAILED';
}TransactionBroadcastError
Thrown when transaction broadcast fails:
class TransactionBroadcastError extends X402Error {
code: 'TRANSACTION_BROADCAST_FAILED';
}InvalidPaymentRequestError
Thrown when payment request is invalid:
class InvalidPaymentRequestError extends X402Error {
code: 'INVALID_PAYMENT_REQUEST';
}Error Codes Reference
import { ERROR_CODES } from '@shade402/core';
console.log(ERROR_CODES.PAYMENT_REQUIRED);
// {
// code: "PAYMENT_REQUIRED",
// message: "Payment is required to access this resource",
// retry: true,
// user_action: "Ensure wallet has sufficient funds and retry"
// }Client-side Error Handling
Explicit Client
import {
PaymentRequiredError,
PaymentExpiredError,
InsufficientFundsError,
PaymentVerificationError,
TransactionBroadcastError,
} from '@shade402/core';
import { X402Client } from '@shade402/client';
const client = new X402Client(wallet);
try {
let response = await client.get(url);
if (client.paymentRequired(response)) {
const paymentRequest = client.parsePaymentRequest(response);
if (paymentRequest.isExpired()) {
throw new PaymentExpiredError(paymentRequest);
}
try {
const authorization = await client.createPayment(paymentRequest);
response = await client.get(url, { payment: authorization });
} catch (error) {
if (error instanceof InsufficientFundsError) {
console.error('Insufficient funds:', error.requiredAmount);
} else if (error instanceof PaymentExpiredError) {
console.error('Payment expired');
} else if (error instanceof TransactionBroadcastError) {
console.error('Transaction broadcast failed:', error.message);
} else {
throw error;
}
}
}
} catch (error) {
if (error instanceof X402Error) {
console.error('X402 error:', error.code, error.message);
} else {
console.error('Unexpected error:', error);
}
} finally {
await client.close();
}Automatic Client
import {
PaymentRequiredError,
InsufficientFundsError,
PaymentExpiredError,
} from '@shade402/core';
import { X402AutoClient } from '@shade402/client';
const client = new X402AutoClient(wallet);
try {
const response = await client.get(url);
} catch (error) {
if (error instanceof PaymentRequiredError) {
// Payment required but autoRetry is false
console.log('Payment required:', error.paymentRequest);
} else if (error instanceof InsufficientFundsError) {
console.error('Insufficient funds:', error.requiredAmount);
console.error('Available:', error.availableAmount);
} else if (error instanceof PaymentExpiredError) {
console.error('Payment expired');
} else {
console.error('Unexpected error:', error);
}
} finally {
await client.close();
}Server-side Error Handling
Express Middleware
import { x402ErrorMiddleware } from '@shade402/express';
// Add error middleware after all routes
app.use(x402ErrorMiddleware({
logErrors: true,
includeStack: process.env.NODE_ENV === 'development',
onError: (error, req, res) => {
// Custom error handling
console.error('Error:', error);
},
}));The error middleware automatically:
Returns 402 for
PaymentRequiredErrorReturns 410 for
PaymentExpiredErrorReturns 403 for
PaymentVerificationErrorReturns 502 for
TransactionBroadcastErrorReturns 400 for
InvalidPaymentRequestErrorReturns 500 for other errors
Manual Error Handling
import {
PaymentVerificationError,
PaymentExpiredError,
} from '@shade402/core';
app.get('/api/data',
paymentRequired({ amount: '0.01' }),
async (req, res) => {
try {
// Your logic
} catch (error) {
if (error instanceof PaymentVerificationError) {
return res.status(403).json({
error: 'Payment verification failed',
code: error.code,
});
} else if (error instanceof PaymentExpiredError) {
return res.status(410).json({
error: 'Payment expired',
code: error.code,
});
} else {
return res.status(500).json({
error: 'Internal server error',
});
}
}
}
);Error Response Format
Standard error response format:
{
"error": "Error message",
"code": "ERROR_CODE",
"details": {
// Additional error details
}
}Example Responses
// 402 Payment Required
{
"error": "Payment is required to access this resource",
"code": "PAYMENT_REQUIRED",
"payment_request": {
"max_amount_required": "0.01",
// ... payment request details
}
}
// 403 Payment Verification Failed
{
"error": "Payment verification failed: transaction not found",
"code": "PAYMENT_VERIFICATION_FAILED"
}
// 410 Payment Expired
{
"error": "Payment request has expired",
"code": "PAYMENT_EXPIRED",
"payment_request": {
// ... payment request details
}
}Best Practices
Handle all error types: Catch and handle specific error types
Provide helpful messages: Return clear error messages to clients
Log errors: Log errors for debugging and monitoring
Don't expose sensitive info: Don't expose internal details in error messages
Use error codes: Use error codes for programmatic error handling
Retry appropriately: Retry transient errors, not permanent ones
Monitor errors: Set up monitoring and alerts for errors
Error Monitoring
import { x402ErrorMiddleware } from '@shade402/express';
app.use(x402ErrorMiddleware({
logErrors: true,
onError: (error, req, res) => {
// Send to monitoring service
monitoringService.captureException(error, {
tags: {
type: 'x402_error',
code: error.code,
},
extra: {
path: req.path,
method: req.method,
},
});
},
}));Next Steps
Review Best Practices for error handling patterns
Check out Troubleshooting for common issues
See Examples for error handling examples
Last updated
