Custom Error Messages
Use #[msg("...")] on error enum variants for default messages. Clients map error codes to localized copy using the IDL.
Search across all documentation pages
Use #[msg("...")] on error enum variants for default messages. Clients map error codes to localized copy using the IDL.
#[error_code]
pub enum SwapError {
#[msg("Slippage tolerance exceeded")]
SlippageExceeded,
#[msg("Pool is disabled")]
PoolDisabled,
}When to reach for this: You ship user-facing dApps that display program failures.
#[error_code]
pub enum StakeError {
#[msg("Stake amount below minimum")]
BelowMinimum,
#[msg("Unlock period not elapsed")]
StillLocked,
}
// constraint errors
#[account(constraint = !pool.disabled @ SwapError::PoolDisabled)]
pub pool: Account<'info, Pool>,What this demonstrates:
Generate error lookup tables from IDL in TypeScript. Show error.errorCode + mapped message in UI.
Do not renumber error variants lightly; clients cache mappings.
| Alternative | Use When | Don't Use When |
|---|---|---|
| Events for failure context | Rich details | Simple user messages |
| Error metadata off-chain | Localization tables | On-chain canonical codes |
Custom codes in IDL plus #[msg] strings.
emit_cpi! costs more CU but improves capture reliability.
Avoid except behind feature flags.
From IDL via Anchor or Codama codegen.
Yes, #[event] types are listed.
Yes with @ MyError::Variant.
Each log line and formatted string.
anchor test expecting error codes.
Yes, but not an API contract; use events.
See Related for error messages.
Stack versions: This page was written for Agave 4.1.1, Solana CLI 3.0.10, Anchor 0.32.1, anchor-lang 0.32.1, Rust 1.91.1, @solana/kit 7.0.0, Surfpool 0.12.0, and LiteSVM 0.6.x.
Reviewed by Chris St. John·Last updated Jul 19, 2026