Troubleshooting
Common issues and solutions when using Shade402.
Payment Issues
Payment Not Detected
Problem: Server doesn't detect payment authorization.
Solutions:
Check that
X-Payment-Authorizationheader is includedVerify header is base64-encoded JSON
Check that payment authorization format is correct
Ensure middleware is processing the header
// Debug: Log headers
app.use((req, res, next) => {
console.log('Headers:', req.headers);
next();
});Payment Verification Fails
Problem: Payment verification fails even though transaction exists.
Solutions:
Check RPC endpoint is correct and accessible
Verify network matches (devnet vs mainnet)
Ensure transaction is confirmed on blockchain
Check transaction signature is valid
Verify payment addresses match
// Enable detailed logging
initX402({
// ... config ...
autoVerify: true,
});
// Check transaction manually
const processor = new SolanaPaymentProcessor(rpcUrl);
const isValid = await processor.verifyPayment(request, authorization);
console.log('Verification result:', isValid);Payment Expired
Problem: Payment request expires before payment is made.
Solutions:
Increase expiration time
Make payment faster
Check system clock synchronization
Use shorter expiration for automated flows
// Increase expiration time
paymentRequired({
amount: '0.01',
expiresIn: 600, // 10 minutes instead of default 5
});Insufficient Funds
Problem: Wallet doesn't have enough tokens.
Solutions:
Check wallet balance
Ensure correct token mint address
Verify token account exists
Add funds to wallet
// Check balance
const processor = new SolanaPaymentProcessor(rpcUrl);
const balance = await processor.getTokenBalance(
walletPublicKey,
tokenMint
);
console.log('Balance:', balance);Client Issues
Cannot Connect to RPC
Problem: Client cannot connect to Solana RPC endpoint.
Solutions:
Check RPC URL is correct
Verify network connectivity
Try different RPC endpoint
Check rate limits on RPC provider
// Test RPC connection
const connection = new Connection(rpcUrl);
const version = await connection.getVersion();
console.log('RPC version:', version);Transaction Broadcast Fails
Problem: Transaction fails to broadcast.
Solutions:
Check network congestion
Verify recent blockhash
Ensure sufficient SOL for fees
Retry transaction
// Retry with new blockhash
try {
const txHash = await processor.signAndSendTransaction(tx, wallet);
} catch (error) {
// Retry with new transaction
const newTx = await processor.createPaymentTransaction(request, amount, wallet);
const txHash = await processor.signAndSendTransaction(newTx, wallet);
}URL Validation Errors
Problem: Client rejects localhost URLs.
Solutions:
Enable
allowLocalfor developmentUse production URLs in production
Check URL format is correct
// For local development only
const client = new X402Client(wallet, rpcUrl, undefined, true);Server Issues
402 Response Not Sent
Problem: Server doesn't send 402 response when payment required.
Solutions:
Check middleware is applied correctly
Verify payment authorization header is missing
Ensure error middleware is after routes
Check middleware order
// Verify middleware order
app.use(express.json());
app.use(paymentRequired({ amount: '0.01' })); // Route-specific
app.use(x402ErrorMiddleware()); // After all routesPayment Authorization Not Parsed
Problem: Server cannot parse payment authorization.
Solutions:
Check header format is correct
Verify base64 encoding
Check JSON structure
Validate all required fields
// Debug: Log raw header
const authHeader = req.headers['x-payment-authorization'];
console.log('Raw header:', authHeader);
try {
const authorization = PaymentAuthorization.fromHeader(authHeader);
} catch (error) {
console.error('Parse error:', error);
}Resource Encryption Fails
Problem: Resource encryption/decryption fails.
Solutions:
Verify RSA keys are correct format
Check keys are PEM format
Ensure public/private key pair matches
Verify encryption algorithm compatibility
// Test encryption
const { publicKey, privateKey } = generateKeyPair();
const encrypted = encryptResource('test', publicKey);
const decrypted = decryptResource(encrypted, privateKey);
console.log('Decrypted:', decrypted); // Should be 'test'Configuration Issues
Configuration Not Initialized
Problem: Error that X402 is not initialized.
Solutions:
Call
initX402()before using middlewareEnsure initialization happens once at startup
Check configuration values are set
// Initialize at startup
initX402({
paymentAddress: process.env.PAYMENT_WALLET_ADDRESS!,
tokenMint: process.env.TOKEN_MINT!,
network: process.env.SOLANA_NETWORK!,
});
// Check if initialized
import { isInitialized } from '@shade402/express';
console.log('Initialized:', isInitialized());Environment Variables Not Loaded
Problem: Configuration values are undefined.
Solutions:
Check
.envfile existsVerify environment variables are loaded
Use
dotenvpackage if neededCheck variable names match
// Load environment variables
import 'dotenv/config';
// Verify variables
console.log('Payment address:', process.env.PAYMENT_WALLET_ADDRESS);
console.log('Token mint:', process.env.TOKEN_MINT);Network Issues
Wrong Network
Problem: Using wrong Solana network.
Solutions:
Check network configuration matches
Verify devnet vs mainnet
Ensure RPC endpoint matches network
Check token mint matches network
// Verify network
const network = process.env.SOLANA_NETWORK;
console.log('Network:', network);
// Devnet token mint
const devnetMint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';
// Mainnet token mint (same for USDC)
const mainnetMint = 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v';RPC Rate Limiting
Problem: RPC endpoint rate limits exceeded.
Solutions:
Use different RPC provider
Implement rate limiting
Add retry logic with backoff
Use premium RPC service
// Retry with exponential backoff
async function retryWithBackoff(fn: () => Promise<any>, retries = 3) {
for (let i = 0; i < retries; i++) {
try {
return await fn();
} catch (error) {
if (i === retries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, Math.pow(2, i) * 1000));
}
}
}TypeScript Issues
Type Errors
Problem: TypeScript compilation errors.
Solutions:
Install type definitions
Check TypeScript version
Verify import paths
Use correct type annotations
// Correct imports
import { X402Request } from '@shade402/express';
import { PaymentAuthorization } from '@shade402/core';
// Use types
app.get('/api/data',
paymentRequired({ amount: '0.01' }),
(req: X402Request, res) => {
const payment: PaymentAuthorization | undefined = req.payment;
}
);Debugging Tips
Enable Verbose Logging
// Client-side
const client = new X402AutoClient(wallet, rpcUrl, {
// Enable detailed logging in development
});
// Server-side
app.use((req, res, next) => {
console.log('Request:', req.method, req.path);
console.log('Headers:', req.headers);
next();
});Check Transaction Status
// Verify transaction on blockchain
const connection = new Connection(rpcUrl);
const signature = authorization.transactionHash;
const status = await connection.getSignatureStatus(signature);
console.log('Transaction status:', status);Test Payment Flow Manually
// Step-by-step testing
const client = new X402Client(wallet);
// 1. Make request
const response = await client.get(url);
console.log('Status:', response.status);
// 2. Parse payment request
if (client.paymentRequired(response)) {
const request = client.parsePaymentRequest(response);
console.log('Payment request:', request);
// 3. Create payment
const authorization = await client.createPayment(request);
console.log('Authorization:', authorization);
// 4. Retry
const retryResponse = await client.get(url, { payment: authorization });
console.log('Retry status:', retryResponse.status);
}Getting Help
If you're still experiencing issues:
Check the Examples for working code
Review Best Practices for common patterns
Check Security for configuration issues
Open an issue on GitHub with:
Error messages
Code snippets
Configuration (without secrets)
Network and environment details
Next Steps
Review Best Practices
Check out Examples for reference
See Security for configuration
Last updated
