Error Handling
Classify, parse, and recover from errors in your SDK integration.
Error categories
SDK errors fall into five categories. Match on error message strings to classify:
Insufficient funds
User doesn't have enough USDC balance.
typescript
try {
await sdk.placeWagerV2({ bet, amount: 1000, side: Outcome.For, signers });
} catch (error) {
if ((error as Error).message.includes("insufficient funds") ||
(error as Error).message.includes("0x1")) {
console.log("Not enough USDC to place this wager");
}
}Invalid state
Operation not allowed in current bet state (e.g. wager on a resolved bet).
typescript
} catch (error) {
if ((error as Error).message.includes("not pending")) {
console.log("Bet is no longer accepting wagers");
} else if ((error as Error).message.includes("already resolving")) {
console.log("Voting has already started");
}
}Account not found
The requested on-chain account doesn't exist.
typescript
try {
await sdk.accounts.betV2.single(invalidAddress);
} catch (error) {
if ((error as Error).message.includes("Account does not exist")) {
console.log("Bet not found at this address");
}
}Network errors
RPC timeouts or blockhash expiry — these are typically retryable.
typescript
} catch (error) {
if ((error as Error).message.includes("blockhash not found")) {
console.log("Transaction expired, please retry");
} else if ((error as Error).message.includes("timeout")) {
console.log("Network error, please try again");
}
}Error parser
Build a reusable parser to classify errors and generate user-friendly messages:
typescript
interface SDKError {
type:
| "INSUFFICIENT_FUNDS"
| "INVALID_STATE"
| "ACCOUNT_NOT_FOUND"
| "ALREADY_EXISTS"
| "PERMISSION_DENIED"
| "NETWORK"
| "UNKNOWN";
message: string;
original: Error;
}
function parseSDKError(error: Error): SDKError {
const msg = error.message.toLowerCase();
if (msg.includes("insufficient") || msg.includes("0x1")) {
return { type: "INSUFFICIENT_FUNDS", message: "Not enough balance", original: error };
}
if (msg.includes("not pending") || msg.includes("already resolved")) {
return { type: "INVALID_STATE", message: "Operation not allowed in current state", original: error };
}
if (msg.includes("account does not exist")) {
return { type: "ACCOUNT_NOT_FOUND", message: "Account not found", original: error };
}
if (msg.includes("already in use")) {
return { type: "ALREADY_EXISTS", message: "Account already exists", original: error };
}
if (msg.includes("not authorized") || msg.includes("owner mismatch")) {
return { type: "PERMISSION_DENIED", message: "Permission denied", original: error };
}
if (msg.includes("timeout") || msg.includes("blockhash") || msg.includes("failed to send")) {
return { type: "NETWORK", message: "Network error, please try again", original: error };
}
return { type: "UNKNOWN", message: error.message, original: error };
}Usage example
typescript
async function placeWagerSafely(
betAddress: PublicKey,
amount: number,
side: Outcome
) {
try {
const txHash = await sdk.placeWagerV2({ bet: betAddress, amount, side, signers: [wallet] });
return { success: true, txHash };
} catch (error) {
const parsed = parseSDKError(error as Error);
switch (parsed.type) {
case "INSUFFICIENT_FUNDS":
return { success: false, error: "Please add more USDC" };
case "INVALID_STATE":
return { success: false, error: "Bet is no longer accepting wagers" };
case "NETWORK":
return { success: false, error: "Please check your connection and retry" };
default:
console.error("Unexpected error:", parsed.original);
return { success: false, error: "Something went wrong" };
}
}
}Program error codes
Common Anchor error codes that appear in error messages:
| Code | Description |
|---|---|
| 0x0 | Generic error |
| 0x1 | Insufficient funds |
| 0x64 (100) | Account already initialized |
| 0x65 (101) | Invalid state transition |
| 0x66 (102) | Unauthorized |
| 0x67 (103) | Invalid argument |
Pre-send validation
Validate conditions before sending transactions to surface errors earlier and avoid wasted gas:
typescript
async function validateWager(
betAddress: PublicKey,
amount: number
): Promise<{ valid: boolean; error?: string }> {
// Check bet state
const bet = await sdk.accounts.betV2.single(betAddress);
if (bet.status !== MarketStatus.Pending) {
return { valid: false, error: "Bet is not accepting wagers" };
}
// Check user balance
const tokenAccount = await getAccount(connection, userTokenAddress);
const balance = Number(tokenAccount.amount) / 1e6;
if (balance < amount) {
return { valid: false, error: `Insufficient balance: ${balance} USDC` };
}
// Check user has a program account
try {
await sdk.accounts.user.single(sdk.addresses.user.get(wallet.publicKey));
} catch {
return { valid: false, error: "Please create a program user first" };
}
return { valid: true };
}