Documentation Index
Fetch the complete documentation index at: https://mintlify.com/solana-foundation/anchor/llms.txt
Use this file to discover all available pages before exploring further.
Proper error handling is crucial for building robust Solana programs. Anchor provides a comprehensive error handling system with custom errors, built-in framework errors, and helpful macros for validation.
Error Types in Anchor
Anchor errors fall into two main categories:
- Framework Errors: Built-in errors from Anchor (error codes 100-5000)
- Custom Errors: Program-specific errors you define (starting at 6000)
The Error Enum
Anchor’s error type is defined as:
pub enum Error {
AnchorError(Box<AnchorError>),
ProgramError(Box<ProgramErrorWithOrigin>),
}
Defining Custom Errors
Use the #[error_code] attribute to define custom errors:
#[error_code]
pub enum ErrorCode {
#[msg("The provided value is too large")]
ValueTooLarge,
#[msg("The provided value is too small")]
ValueTooSmall,
#[msg("Unauthorized access attempt")]
Unauthorized,
#[msg("Insufficient funds for this operation")]
InsufficientFunds,
}
Error Code Numbers
Custom errors are automatically assigned codes starting from 6000:
ValueTooLarge = 6000
ValueTooSmall = 6001
Unauthorized = 6002
InsufficientFunds = 6003
Framework error code ranges:
| Range | Description |
|---|
| >= 100 | Instruction errors |
| >= 1000 | IDL errors |
| >= 2000 | Constraint errors |
| >= 3000 | Account errors |
| >= 4100 | Miscellaneous errors |
| >= 6000 | Custom user errors |
Returning Errors
Using err! Macro
The err! macro returns an error from your instruction:
pub fn set_value(ctx: Context<SetValue>, value: u64) -> Result<()> {
if value > 100 {
return err!(ErrorCode::ValueTooLarge);
}
ctx.accounts.my_account.value = value;
Ok(())
}
Using require! Macro
The require! macro provides a concise way to validate conditions:
pub fn set_value(ctx: Context<SetValue>, value: u64) -> Result<()> {
require!(value <= 100, ErrorCode::ValueTooLarge);
require!(value >= 10, ErrorCode::ValueTooSmall);
ctx.accounts.my_account.value = value;
Ok(())
}
If the condition is false, require! returns the specified error.
Validation Macros
Anchor provides several macros for common validation patterns:
require!
Ensures a condition is true:
require!(amount > 0, ErrorCode::InvalidAmount);
require_eq!
Ensures two values are equal:
require_eq!(account.owner, authority.key(), ErrorCode::Unauthorized);
require_neq!
Ensures two values are not equal:
require_neq!(from.key(), to.key(), ErrorCode::SameAccount);
require_keys_eq!
Ensures two Pubkeys are equal:
require_keys_eq!(account.authority, authority.key(), ErrorCode::Unauthorized);
require_keys_neq!
Ensures two Pubkeys are not equal:
require_keys_neq!(sender.key(), receiver.key(), ErrorCode::CannotSendToSelf);
require_gt!
Ensures the first value is greater than the second:
require_gt!(new_amount, old_amount, ErrorCode::AmountNotIncreased);
require_gte!
Ensures the first value is greater than or equal to the second:
require_gte!(balance, amount, ErrorCode::InsufficientFunds);
Complete Example
Here’s a comprehensive example demonstrating error handling:
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod vault {
use super::*;
pub fn initialize(ctx: Context<Initialize>, max_amount: u64) -> Result<()> {
require!(max_amount > 0, ErrorCode::InvalidMaxAmount);
let vault = &mut ctx.accounts.vault;
vault.authority = ctx.accounts.authority.key();
vault.balance = 0;
vault.max_amount = max_amount;
msg!("Vault initialized with max amount: {}", max_amount);
Ok(())
}
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
require!(amount > 0, ErrorCode::InvalidAmount);
let vault = &mut ctx.accounts.vault;
let new_balance = vault.balance
.checked_add(amount)
.ok_or(ErrorCode::Overflow)?;
require!(new_balance <= vault.max_amount, ErrorCode::ExceedsMaxAmount);
vault.balance = new_balance;
msg!("Deposited {}. New balance: {}", amount, vault.balance);
Ok(())
}
pub fn withdraw(
ctx: Context<Withdraw>,
amount: u64,
) -> Result<()> {
require!(amount > 0, ErrorCode::InvalidAmount);
require_gte!(ctx.accounts.vault.balance, amount, ErrorCode::InsufficientFunds);
let vault = &mut ctx.accounts.vault;
vault.balance = vault.balance
.checked_sub(amount)
.ok_or(ErrorCode::Underflow)?;
msg!("Withdrew {}. Remaining balance: {}", amount, vault.balance);
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init,
payer = authority,
space = 8 + Vault::INIT_SPACE
)]
pub vault: Account<'info, Vault>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut)]
pub vault: Account<'info, Vault>,
}
#[derive(Accounts)]
pub struct Withdraw<'info> {
#[account(
mut,
has_one = authority @ ErrorCode::Unauthorized
)]
pub vault: Account<'info, Vault>,
pub authority: Signer<'info>,
}
#[account]
#[derive(InitSpace)]
pub struct Vault {
pub authority: Pubkey,
pub balance: u64,
pub max_amount: u64,
}
#[error_code]
pub enum ErrorCode {
#[msg("Amount must be greater than zero")]
InvalidAmount,
#[msg("Max amount must be greater than zero")]
InvalidMaxAmount,
#[msg("Insufficient funds in vault")]
InsufficientFunds,
#[msg("Deposit would exceed maximum vault amount")]
ExceedsMaxAmount,
#[msg("Only the authority can perform this action")]
Unauthorized,
#[msg("Arithmetic overflow occurred")]
Overflow,
#[msg("Arithmetic underflow occurred")]
Underflow,
}
Error Responses
When an error occurs, Anchor provides detailed information in the transaction logs:
Program log: AnchorError thrown in programs/vault/src/lib.rs:25.
Error Code: InsufficientFunds.
Error Number: 6002.
Error Message: Insufficient funds in vault.
Client-Side Error Handling
In TypeScript clients, catch and handle errors:
try {
await program.methods
.withdraw(new anchor.BN(1000))
.accounts({ vault, authority })
.rpc();
} catch (error) {
if (error.error.errorCode.code === 'InsufficientFunds') {
console.log('Not enough funds in vault');
console.log('Error message:', error.error.errorMessage);
}
}
Error response structure:
{
error: {
errorCode: { code: 'InsufficientFunds', number: 6002 },
errorMessage: 'Insufficient funds in vault',
origin: { file: 'programs/vault/src/lib.rs', line: 25 }
},
logs: [...],
errorLogs: [...]
}
Common Framework Errors
Some frequently encountered Anchor framework errors:
| Error | Code | Description |
|---|
| ConstraintMut | 2000 | Account should be mutable |
| ConstraintHasOne | 2001 | has_one constraint violated |
| ConstraintSigner | 2002 | Account should be a signer |
| ConstraintOwner | 2004 | Wrong account owner |
| ConstraintSeeds | 2006 | PDA seeds don’t match |
| AccountNotInitialized | 3012 | Account not initialized |
| RequireViolated | 2500 | require! condition failed |
Best Practices
- Use descriptive error messages: Make errors easy to understand and debug
- Validate early: Check conditions at the start of instructions
- Use specific errors: Create distinct error codes for different failure cases
- Leverage constraints: Use account constraints for validation when possible
- Check arithmetic: Use checked operations to prevent overflows
- Document errors: Add comments explaining when each error is used
- Test error cases: Write tests that verify error conditions
Using Constraints for Validation
Many validations can be done with account constraints instead of manual checks:
#[derive(Accounts)]
pub struct Withdraw<'info> {
#[account(
mut,
has_one = authority @ ErrorCode::Unauthorized,
constraint = vault.balance >= amount @ ErrorCode::InsufficientFunds
)]
pub vault: Account<'info, Vault>,
pub authority: Signer<'info>,
}
This approach is more concise and errors are caught during account validation.