Error Handling Guide
This guide covers all error types, when they occur, and how to handle them properly.
Error Types
The SDK uses specific error classes for different scenarios, making error handling straightforward.
Error Class Hierarchy
ArcadiaSDKError (base class)
├── WalletNotConnectedError
├── PaymentFailedError
├── TimeoutError
├── InvalidConfigError
├── NotInIframeError
├── InvalidAmountError
└── InvalidTokenError
Error Types
WalletNotConnectedError
When it occurs:
- Calling
getWalletAddress()when wallet is not connected - Attempting payment operations without a connected wallet
- Wallet disconnects during an operation
Error code: WALLET_NOT_CONNECTED
Example:
import { WalletNotConnectedError } from '@arcadiasol/sdk';
try {
const address = await arcadia.getWalletAddress();
} catch (error) {
if (error instanceof WalletNotConnectedError) {
showMessage('Please connect your wallet in Arcadia');
}
}
Handling:
const walletAddress = await arcadia.getWalletAddress();
if (!walletAddress) {
// Wallet not connected - show prompt
showWalletConnectionPrompt();
return;
}
PaymentFailedError
When it occurs:
- Transaction is rejected by user
- Transaction fails on blockchain
- Insufficient funds
- Network errors
- Developer wallet not configured
Error code: PAYMENT_FAILED
Properties:
message- Error messagetxSignature- Transaction signature (if available)
Example:
import { PaymentFailedError } from '@arcadiasol/sdk';
try {
const result = await arcadia.payment.payToPlay(0.5, 'SOL');
} catch (error) {
if (error instanceof PaymentFailedError) {
console.error('Payment failed:', error.message);
if (error.txSignature) {
console.log('Transaction:', error.txSignature);
}
showError('Payment failed: ' + error.message);
}
}
Handling:
async function processPayment(amount: number) {
try {
const result = await arcadia.payment.payToPlay(amount, 'SOL');
return result;
} catch (error) {
if (error instanceof PaymentFailedError) {
// Check specific error message
if (error.message.includes('insufficient funds')) {
showError('Insufficient balance. Please add funds to your wallet.');
} else if (error.message.includes('user rejected')) {
showError('Payment cancelled');
} else {
showError('Payment failed: ' + error.message);
}
return null;
}
throw error;
}
}
TimeoutError
When it occurs:
- Request to parent window times out
- Network issues prevent communication
- Parent window is unresponsive
Error code: TIMEOUT
Example:
import { TimeoutError } from '@arcadiasol/sdk';
try {
const address = await arcadia.getWalletAddress();
} catch (error) {
if (error instanceof TimeoutError) {
showError('Request timed out. Please try again.');
// Retry logic
setTimeout(() => retryGetWalletAddress(), 1000);
}
}
Handling:
async function getWalletAddressWithRetry(maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
return await arcadia.getWalletAddress();
} catch (error) {
if (error instanceof TimeoutError && i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
continue;
}
throw error;
}
}
}
InvalidConfigError
When it occurs:
gameIdis missing or empty- Invalid configuration values
Error code: INVALID_CONFIG
Example:
import { InvalidConfigError } from '@arcadiasol/sdk';
try {
const arcadia = new ArcadiaSDK({
gameId: '', // Invalid - empty string
});
} catch (error) {
if (error instanceof InvalidConfigError) {
console.error('Invalid SDK configuration:', error.message);
}
}
Handling:
function createSDK(gameId: string) {
if (!gameId || gameId.trim().length === 0) {
throw new Error('gameId is required');
}
try {
return new ArcadiaSDK({ gameId });
} catch (error) {
if (error instanceof InvalidConfigError) {
console.error('SDK configuration error:', error.message);
throw new Error('Failed to initialize SDK');
}
throw error;
}
}
NotInIframeError
When it occurs:
- Calling SDK methods outside of Arcadia's iframe
- Testing SDK in standalone environment
Error code: NOT_IN_IFRAME
Example:
import { NotInIframeError } from '@arcadiasol/sdk';
try {
const result = await arcadia.payment.payToPlay(0.5, 'SOL');
} catch (error) {
if (error instanceof NotInIframeError) {
console.warn('SDK must run in Arcadia iframe');
// Fallback for testing
useMockPayment();
}
}
Handling:
if (!arcadia.isInIframe()) {
console.warn('SDK is not running in iframe - some features may not work');
// Use mock or test mode
}
InvalidAmountError
When it occurs:
- Payment amount is 0 or negative
- Payment amount is not a number
- Payment amount is NaN
Error code: INVALID_AMOUNT
Example:
import { InvalidAmountError } from '@arcadiasol/sdk';
try {
await arcadia.payment.payToPlay(-1, 'SOL'); // Invalid
} catch (error) {
if (error instanceof InvalidAmountError) {
showError('Payment amount must be greater than 0');
}
}
Handling:
function validateAmount(amount: number): boolean {
if (typeof amount !== 'number' || isNaN(amount) || amount <= 0) {
showError('Invalid payment amount');
return false;
}
return true;
}
const amount = parseFloat(userInput);
if (validateAmount(amount)) {
await arcadia.payment.payToPlay(amount, 'SOL');
}
InvalidTokenError
When it occurs:
- Token type is not 'SOL' or 'USDC'
- Token type is invalid
Error code: INVALID_TOKEN
Example:
import { InvalidTokenError } from '@arcadiasol/sdk';
try {
await arcadia.payment.payToPlay(0.5, 'BTC'); // Invalid
} catch (error) {
if (error instanceof InvalidTokenError) {
showError('Invalid token. Use SOL or USDC');
}
}
Handling:
function validateToken(token: string): token is 'SOL' | 'USDC' {
return token === 'SOL' || token === 'USDC';
}
const token = userSelectedToken;
if (validateToken(token)) {
await arcadia.payment.payToPlay(amount, token);
} else {
showError('Invalid token type');
}
Error Handling Patterns
Pattern 1: Try-Catch with Type Checking
import {
WalletNotConnectedError,
PaymentFailedError,
TimeoutError,
} from '@arcadiasol/sdk';
try {
const result = await arcadia.payment.payToPlay(0.5, 'SOL');
// Success
} catch (error) {
if (error instanceof WalletNotConnectedError) {
showMessage('Please connect your wallet');
} else if (error instanceof PaymentFailedError) {
showError('Payment failed: ' + error.message);
} else if (error instanceof TimeoutError) {
showError('Request timed out. Please try again.');
} else {
showError('An unexpected error occurred');
console.error('Unknown error:', error);
}
}
Pattern 2: Error Handler Utility
class ErrorHandler {
static handle(error: unknown): void {
if (error instanceof WalletNotConnectedError) {
this.showWalletPrompt();
} else if (error instanceof PaymentFailedError) {
this.showPaymentError(error);
} else if (error instanceof TimeoutError) {
this.showTimeoutError();
} else if (error instanceof InvalidAmountError) {
this.showAmountError();
} else if (error instanceof InvalidTokenError) {
this.showTokenError();
} else {
this.showGenericError(error);
}
}
private static showWalletPrompt() {
// Show wallet connection UI
}
private static showPaymentError(error: PaymentFailedError) {
// Show payment error with details
console.error('Payment failed:', error.message);
if (error.txSignature) {
console.log('Transaction:', error.txSignature);
}
}
private static showTimeoutError() {
// Show timeout message
}
private static showAmountError() {
// Show amount validation error
}
private static showTokenError() {
// Show token validation error
}
private static showGenericError(error: unknown) {
// Show generic error
console.error('Error:', error);
}
}
// Usage
try {
await arcadia.payment.payToPlay(0.5, 'SOL');
} catch (error) {
ErrorHandler.handle(error);
}
Pattern 3: Retry Logic
async function payToPlayWithRetry(
amount: number,
maxRetries = 3
): Promise<PaymentResult | null> {
for (let i = 0; i < maxRetries; i++) {
try {
return await arcadia.payment.payToPlay(amount, 'SOL');
} catch (error) {
if (error instanceof TimeoutError && i < maxRetries - 1) {
// Retry on timeout
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
continue;
} else if (error instanceof PaymentFailedError) {
// Don't retry payment failures
throw error;
} else {
// Unknown error - retry
if (i < maxRetries - 1) {
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
continue;
}
throw error;
}
}
}
return null;
}
Common Error Scenarios
Wallet Not Connected
// Always check before operations
const walletAddress = await arcadia.getWalletAddress();
if (!walletAddress) {
showMessage('Please connect your wallet in Arcadia');
return;
}
// Or use try-catch
try {
const result = await arcadia.payment.payToPlay(0.5, 'SOL');
} catch (error) {
if (error instanceof WalletNotConnectedError) {
showWalletConnectionPrompt();
}
}
Payment Rejected by User
try {
const result = await arcadia.payment.payToPlay(0.5, 'SOL');
} catch (error) {
if (error instanceof PaymentFailedError) {
if (error.message.includes('user rejected') ||
error.message.includes('cancelled')) {
// User cancelled - don't show error, just return
return;
}
showError('Payment failed: ' + error.message);
}
}
Insufficient Funds
try {
const result = await arcadia.payment.payToPlay(0.5, 'SOL');
} catch (error) {
if (error instanceof PaymentFailedError) {
if (error.message.includes('insufficient funds') ||
error.message.includes('insufficient balance')) {
showError('Insufficient balance. Please add funds to your wallet.');
} else {
showError('Payment failed: ' + error.message);
}
}
}
Debugging Tips
- Check Error Messages - Error messages contain useful information
- Log Transaction Signatures - Payment errors may include transaction signatures
- Verify SDK State - Check
isInitialized()andisInIframe() - Check Wallet Status - Verify wallet is connected before operations
- Network Issues - Timeout errors often indicate network problems
Next Steps
- Review API Reference for complete error class documentation
- See Examples for error handling patterns
- Check Security for security-related error handling