123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321 |
- ---
- title: Custom Errors
- description: Learn how to implement custom error handling in Anchor programs.
- ---
- All instruction handlers in Anchor programs return a custom `Result<T>` type
- that allows you to handle successful execution with `Ok(T)` and error cases with
- `Err(Error)`.
- ```rust
- // [!code word:Result]
- pub fn custom_instruction(ctx: Context<CustomInstruction>) -> Result<()> {
- // --snip--
- Ok(())
- }
- ```
- The
- [`Result<T>`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/lib.rs#L74)
- type in Anchor programs is a type alias that wraps the standard Rust
- `Result<T, E>`. In this case, `T` represents the successful return type, while
- `E` is Anchor's custom `Error` type.
- ```rust
- pub type Result<T> = std::result::Result<T, error::Error>;
- ```
- ## Anchor Error
- When an error occurs in an Anchor program, it returns a custom
- [`Error`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/error.rs#L277-L281)
- type defined as:
- ```rust
- #[derive(Debug, PartialEq, Eq)]
- pub enum Error {
- AnchorError(Box<AnchorError>),
- ProgramError(Box<ProgramErrorWithOrigin>),
- }
- ```
- The `Error` type in Anchor programs can be one of two variants:
- 1. [`ProgramErrorWithOrigin`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/error.rs#L389-L394):
- Custom type that wraps a standard Solana
- [`ProgramError`](https://github.com/anza-xyz/agave/blob/v1.18.26/sdk/program/src/program_error.rs#L12-L66)
- type. These errors come from the `solana_program` crate.
- ```rust
- #[derive(Debug)]
- pub struct ProgramErrorWithOrigin {
- pub program_error: ProgramError,
- pub error_origin: Option<ErrorOrigin>,
- pub compared_values: Option<ComparedValues>,
- }
- ```
- 2. [`AnchorError`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/error.rs#L490-L497):
- Errors defined by the Anchor framework.
- ```rust
- #[derive(Debug)]
- pub struct AnchorError {
- pub error_name: String,
- pub error_code_number: u32,
- pub error_msg: String,
- pub error_origin: Option<ErrorOrigin>,
- pub compared_values: Option<ComparedValues>,
- }
- ```
- An `AnchorError` can be thought of as having two categories:
- 1. Internal Anchor Errors - These are built-in errors included with the Anchor
- framework. They are defined in the
- [`ErrorCode`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/error.rs#L10-L275)
- enum.
- 2. Custom Program Errors - These are program specific errors that developers
- define to handle custom error cases.
- The `error_code_number` from an `AnchorError` has the following numbering
- scheme:
- | Error Code | Description |
- | ---------- | ------------------------------------- |
- | >= 100 | Instruction error codes |
- | >= 1000 | IDL error codes |
- | >= 2000 | Constraint error codes |
- | >= 3000 | Account error codes |
- | >= 4100 | Misc error codes |
- | = 5000 | Deprecated error code |
- | >= 6000 | Starting point for custom user errors |
- ## Usage
- Anchor provides a convenient way to define custom errors through the
- `error_code` attribute. The implementation details can be found
- [here](https://github.com/coral-xyz/anchor/blob/master/lang/syn/src/codegen/error.rs).
- When you define an enum with the `error_code` attribute, Anchor automatically:
- - Assigns an error code starting from 6000
- - Generates the necessary boilerplate for error handling
- - Enables the use of custom error messages via the `msg` attribute
- ```rust
- #[error_code]
- pub enum MyError {
- #[msg("My custom error message")]
- MyCustomError,
- #[msg("My second custom error message")]
- MySecondCustomError,
- }
- ```
- ### err!
- To throw an error, use the
- [`err!`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/lib.rs#L720-L728)
- macro. The `err!` macro provides a convenient way to return custom errors from
- your program. Under the hood, `err!` uses the `error!` macro to construct
- `AnchorError`. The implementation can be found
- [here](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/attribute/error/src/lib.rs#L84-L116).
- ```rust
- #[program]
- mod hello_anchor {
- use super::*;
- pub fn set_data(ctx: Context<SetData, data: MyAccount) - Result<()> {
- if data.data = 100 {
- // [!code word:MyError]
- // [!code highlight]
- return err!(MyError::DataTooLarge);
- }
- ctx.accounts.my_account.set_inner(data);
- Ok(())
- }
- }
- #[error_code]
- pub enum MyError {
- #[msg("MyAccount may only hold data below 100")]
- DataTooLarge
- }
- ```
- ### require!
- The
- [`require!`](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/lib.rs#L510-L522)
- macro provides a more concise way to handle error conditions. It combines a
- condition check with returning an error if the condition is false. Here's how we
- can rewrite the previous example using `require!`:
- ```rust
- #[program]
- mod hello_anchor {
- use super::*;
- pub fn set_data(ctx: Context<SetData, data: MyAccount) - Result<()> {
- // [!code word:MyError]
- // [!code highlight]
- require!(data.data < 100, MyError::DataTooLarge);
- ctx.accounts.my_account.set_inner(data);
- Ok(())
- }
- }
- #[error_code]
- pub enum MyError {
- #[msg("MyAccount may only hold data below 100")]
- DataTooLarge
- }
- ```
- Anchor provides several "require" macros for different validation needs. You can
- find the implementation of these macros
- [here](https://github.com/coral-xyz/anchor/blob/v0.30.1/lang/src/lib.rs).
- | Macro | Description |
- | ------------------- | ------------------------------------------------------------------------------------------- |
- | `require!` | Ensures a condition is true, otherwise returns with the given error. |
- | `require_eq!` | Ensures two NON-PUBKEY values are equal. |
- | `require_neq!` | Ensures two NON-PUBKEY values are not equal. |
- | `require_keys_eq!` | Ensures two pubkeys values are equal. |
- | `require_keys_neq!` | Ensures two pubkeys are not equal. |
- | `require_gt!` | Ensures the first NON-PUBKEY value is greater than the second NON-PUBKEY value. |
- | `require_gte!` | Ensures the first NON-PUBKEY value is greater than or equal to the second NON-PUBKEY value. |
- ## Example
- Here's a simple example demonstrating how to define and handle custom errors in
- an Anchor program. The program below validates that an input amount falls within
- an acceptable range, showing how to:
- - Define custom error types with messages
- - Use the `require!` macro to check conditions and return errors
- <Tabs items={["Program", "Client"]}>
- <Tab value="Program">
- ```rust title="lib.rs"
- use anchor_lang::prelude::*;
- declare_id!("9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV");
- #[program]
- pub mod custom_error {
- use super::*;
- pub fn validate_amount(_ctx: Context<ValidateAmount, amount: u64) - Result<()> {
- // [!code word:CustomError]
- // [!code highlight:2]
- require!(amount = 10, CustomError::AmountTooSmall);
- require!(amount <= 100, CustomError::AmountTooLarge);
- msg!("Amount validated successfully: {}", amount);
- Ok(())
- }
- }
- #[derive(Accounts)]
- pub struct ValidateAmount {}
- #[error_code]
- pub enum CustomError {
- #[msg("Amount must be greater than or equal to 10")]
- AmountTooSmall,
- #[msg("Amount must be less than or equal to 100")]
- AmountTooLarge,
- }
- ```
- </Tab>
- <Tab value="Client">
- ```ts title="test.ts"
- import * as anchor from "@coral-xyz/anchor";
- import { Program } from "@coral-xyz/anchor";
- import { CustomError } from "../target/types/custom_error";
- import assert from "assert";
- describe("custom-error", () = {
- anchor.setProvider(anchor.AnchorProvider.env());
- const program = anchor.workspace.CustomError as Program<CustomError;
- it("Successfully validates amount within range", async () = {
- const tx = await program.methods.validateAmount(new anchor.BN(50)).rpc();
- console.log("Transaction signature:", tx);
- });
- it("Fails with amount too small", async () = {
- try {
- await program.methods.validateAmount(new anchor.BN(5)).rpc();
- assert.fail("Expected an error to be thrown");
- } catch (error) {
- assert.strictEqual(error.error.errorCode.code, "AmountTooSmall");
- assert.strictEqual(
- error.error.errorMessage,
- "Amount must be greater than or equal to 10",
- );
- }
- });
- it("Fails with amount too large", async () = {
- try {
- await program.methods.validateAmount(new anchor.BN(150)).rpc();
- assert.fail("Expected an error to be thrown");
- } catch (error) {
- assert.strictEqual(error.error.errorCode.code, "AmountTooLarge");
- assert.strictEqual(
- error.error.errorMessage,
- "Amount must be less than or equal to 100",
- );
- }
- });
- });
- ```
- </Tab>
- </Tabs>
- When a program error occurs, Anchor's TypeScript Client SDK returns a detailed
- [error response](https://github.com/coral-xyz/anchor/blob/v0.30.1/ts/packages/anchor/src/error.ts#L51-L71)
- containing information about the error. Here's an example error response showing
- the structure and available fields:
- ```shell title="Error Response"
- {
- errorLogs: [
- 'Program log: AnchorError thrown in programs/custom-error/src/lib.rs:11. Error Code: AmountTooLarge. Error Number: 6001. Error Message: Amount must be less than or equal to 100.'
- ],
- logs: [
- 'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV invoke [1]',
- 'Program log: Instruction: ValidateAmount',
- 'Program log: AnchorError thrown in programs/custom-error/src/lib.rs:11. Error Code: AmountTooLarge. Error Number: 6001. Error Message: Amount must be less than or equal to 100.',
- 'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV consumed 2153 of 200000 compute units',
- 'Program 9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV failed: custom program error: 0x1771'
- ],
- error: {
- errorCode: { code: 'AmountTooLarge', number: 6001 },
- errorMessage: 'Amount must be less than or equal to 100',
- comparedValues: undefined,
- origin: { file: 'programs/custom-error/src/lib.rs', line: 11 }
- },
- _programErrorStack: ProgramErrorStack {
- stack: [
- [PublicKey [PublicKey(9oECKMeeyf1fWNPKzyrB2x1AbLjHDFjs139kEyFwBpoV)]]
- ]
- }
- }
- ```
- For a more comprehensive example, you can also reference the
- [errors test program](https://github.com/coral-xyz/anchor/blob/master/tests/errors/programs/errors/src/lib.rs)
- in the Anchor repository.
|