errors.md 3.2 KB

Errors

There are three types of errors in anchor programs. Anchor Internal Errors, Custom Errors, and non-anchor errors.

The autogenerated clients can automatically parse Anchor Internal Errors and Custom Errors so they can display the error code and error message. This is not possible for non-anchor errors where clients just return the raw error returned by the underlying solana client libraries.

(Ultimately, all programs return the same Error: The ProgramError. This Error has a field for a custom error number. This is where Anchor puts its internal and custom error codes. The autogenerated clients read this number and read the IDL (where custom errors' numbers are mapped to their messages) to display the correct error messages (The Anchor internal error number=>message mapping is hardcoded in the clients). Doing it this way means that there is no way to display dynamic custom error messages because all error messages are hardcoded in the IDL. Very soon, anchor will use logs instead of relying only on the returned error code number to emit errors. These logs can also be read by the client and allow dynamic content.)

Anchor Internal Errors

Anchor Internal Error Code Reference

Anchor has many different internal error codes. These are not meant to be used by users, but it's useful to study the reference to learn about the mappings between codes and their causes. They are, for example, thrown when a constraint has been violated, e.g. when an account is marked with mut but its is_writable property is false.

Custom Errors

You can add errors that are unique to your program by using the error attribute.

Simply add it to an enum with a name of your choice. You can then use the variants of the enum as errors in your program. Additionally, you can add a message attribute to the individual variants. Clients will then display this error message if the error occurs. Custom Error code numbers start at the custom error offset.

#[program]
mod hello_anchor {
    use super::*;
    pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> ProgramResult {
        if data.data >= 100 {
            return Err(MyError::DataTooLarge.into());    
        }
        ctx.accounts.my_account.set_inner(data);
        Ok(())
    }
}


#[error]
pub enum MyError {
    #[msg("MyAccount may only hold data below 100")]
    DataTooLarge
}

You can use the require macro to simplify writing errors. The code above can be simplified to this (Note that the >= flips to <):

#[program]
mod hello_anchor {
    use super::*;
    pub fn set_data(ctx: Context<SetData>, data: MyAccount) -> ProgramResult {
        require!(data.data < 100, MyError::DataTooLarge); 
        ctx.accounts.my_account.set_inner(data);
        Ok(())
    }
}


#[error]
pub enum MyError {
    #[msg("MyAccount may only hold data below 100")]
    DataTooLarge
}