anchor_lang/
error.rs

1use anchor_lang::error_code;
2use borsh::maybestd::io::Error as BorshIoError;
3use solana_program::{program_error::ProgramError, pubkey::Pubkey};
4use std::fmt::{Debug, Display};
5use std::num::TryFromIntError;
6
7/// The starting point for user defined error codes.
8pub const ERROR_CODE_OFFSET: u32 = 6000;
9
10/// Error codes that can be returned by internal framework code.
11///
12/// - >= 100 Instruction error codes
13/// - >= 1000 IDL error codes
14/// - >= 2000 constraint error codes
15/// - >= 3000 account error codes
16/// - >= 4100 misc error codes
17/// - = 5000 deprecated error code
18///
19/// The starting point for user-defined errors is defined
20/// by the [ERROR_CODE_OFFSET](crate::error::ERROR_CODE_OFFSET).
21#[error_code(offset = 0)]
22pub enum ErrorCode {
23    // Instructions
24    /// 100 - Instruction discriminator not provided
25    #[msg("Instruction discriminator not provided")]
26    InstructionMissing = 100,
27    /// 101 - Fallback functions are not supported
28    #[msg("Fallback functions are not supported")]
29    InstructionFallbackNotFound,
30    /// 102 - The program could not deserialize the given instruction
31    #[msg("The program could not deserialize the given instruction")]
32    InstructionDidNotDeserialize,
33    /// 103 - The program could not serialize the given instruction
34    #[msg("The program could not serialize the given instruction")]
35    InstructionDidNotSerialize,
36
37    // IDL instructions
38    /// 1000 - The program was compiled without idl instructions
39    #[msg("The program was compiled without idl instructions")]
40    IdlInstructionStub = 1000,
41    /// 1001 - Invalid program given to the IDL instruction
42    #[msg("Invalid program given to the IDL instruction")]
43    IdlInstructionInvalidProgram,
44    /// 1002 - IDL Account must be empty in order to resize
45    #[msg("IDL account must be empty in order to resize, try closing first")]
46    IdlAccountNotEmpty,
47
48    // Event instructions
49    /// 1500 - The program was compiled without `event-cpi` feature
50    #[msg("The program was compiled without `event-cpi` feature")]
51    EventInstructionStub = 1500,
52
53    // Constraints
54    /// 2000 - A mut constraint was violated
55    #[msg("A mut constraint was violated")]
56    ConstraintMut = 2000,
57    /// 2001 - A has one constraint was violated
58    #[msg("A has one constraint was violated")]
59    ConstraintHasOne,
60    /// 2002 - A signer constraint was violated
61    #[msg("A signer constraint was violated")]
62    ConstraintSigner,
63    /// 2003 - A raw constraint was violated
64    #[msg("A raw constraint was violated")]
65    ConstraintRaw,
66    /// 2004 - An owner constraint was violated
67    #[msg("An owner constraint was violated")]
68    ConstraintOwner,
69    /// 2005 - A rent exemption constraint was violated
70    #[msg("A rent exemption constraint was violated")]
71    ConstraintRentExempt,
72    /// 2006 - A seeds constraint was violated
73    #[msg("A seeds constraint was violated")]
74    ConstraintSeeds,
75    /// 2007 - An executable constraint was violated
76    #[msg("An executable constraint was violated")]
77    ConstraintExecutable,
78    /// 2008 - Deprecated Error, feel free to replace with something else
79    #[msg("Deprecated Error, feel free to replace with something else")]
80    ConstraintState,
81    /// 2009 - An associated constraint was violated
82    #[msg("An associated constraint was violated")]
83    ConstraintAssociated,
84    /// 2010 - An associated init constraint was violated
85    #[msg("An associated init constraint was violated")]
86    ConstraintAssociatedInit,
87    /// 2011 - A close constraint was violated
88    #[msg("A close constraint was violated")]
89    ConstraintClose,
90    /// 2012 - An address constraint was violated
91    #[msg("An address constraint was violated")]
92    ConstraintAddress,
93    /// 2013 - Expected zero account discriminant
94    #[msg("Expected zero account discriminant")]
95    ConstraintZero,
96    /// 2014 - A token mint constraint was violated
97    #[msg("A token mint constraint was violated")]
98    ConstraintTokenMint,
99    /// 2015 - A token owner constraint was violated
100    #[msg("A token owner constraint was violated")]
101    ConstraintTokenOwner,
102    /// The mint mint is intentional -> a mint authority for the mint.
103    ///
104    /// 2016 - A mint mint authority constraint was violated
105    #[msg("A mint mint authority constraint was violated")]
106    ConstraintMintMintAuthority,
107    /// 2017 - A mint freeze authority constraint was violated
108    #[msg("A mint freeze authority constraint was violated")]
109    ConstraintMintFreezeAuthority,
110    /// 2018 - A mint decimals constraint was violated
111    #[msg("A mint decimals constraint was violated")]
112    ConstraintMintDecimals,
113    /// 2019 - A space constraint was violated
114    #[msg("A space constraint was violated")]
115    ConstraintSpace,
116    /// 2020 - A required account for the constraint is None
117    #[msg("A required account for the constraint is None")]
118    ConstraintAccountIsNone,
119    /// The token token is intentional -> a token program for the token account.
120    ///
121    /// 2021 - A token account token program constraint was violated
122    #[msg("A token account token program constraint was violated")]
123    ConstraintTokenTokenProgram,
124    /// 2022 - A mint token program constraint was violated
125    #[msg("A mint token program constraint was violated")]
126    ConstraintMintTokenProgram,
127    /// 2023 - A mint token program constraint was violated
128    #[msg("An associated token account token program constraint was violated")]
129    ConstraintAssociatedTokenTokenProgram,
130    /// Extension constraints
131    ///
132    /// 2024 - A group pointer extension constraint was violated
133    #[msg("A group pointer extension constraint was violated")]
134    ConstraintMintGroupPointerExtension,
135    /// 2025 - A group pointer extension authority constraint was violated
136    #[msg("A group pointer extension authority constraint was violated")]
137    ConstraintMintGroupPointerExtensionAuthority,
138    /// 2026 - A group pointer extension group address constraint was violated
139    #[msg("A group pointer extension group address constraint was violated")]
140    ConstraintMintGroupPointerExtensionGroupAddress,
141    /// 2027 - A group member pointer extension constraint was violated
142    #[msg("A group member pointer extension constraint was violated")]
143    ConstraintMintGroupMemberPointerExtension,
144    /// 2028 - A group member pointer extension authority constraint was violated
145    #[msg("A group member pointer extension authority constraint was violated")]
146    ConstraintMintGroupMemberPointerExtensionAuthority,
147    /// 2029 - A group member pointer extension member address constraint was violated
148    #[msg("A group member pointer extension group address constraint was violated")]
149    ConstraintMintGroupMemberPointerExtensionMemberAddress,
150    /// 2030 - A metadata pointer extension constraint was violated
151    #[msg("A metadata pointer extension constraint was violated")]
152    ConstraintMintMetadataPointerExtension,
153    /// 2031 - A metadata pointer extension authority constraint was violated
154    #[msg("A metadata pointer extension authority constraint was violated")]
155    ConstraintMintMetadataPointerExtensionAuthority,
156    /// 2032 - A metadata pointer extension metadata address constraint was violated
157    #[msg("A metadata pointer extension metadata address constraint was violated")]
158    ConstraintMintMetadataPointerExtensionMetadataAddress,
159    /// 2033 - A close authority extension constraint was violated
160    #[msg("A close authority constraint was violated")]
161    ConstraintMintCloseAuthorityExtension,
162    /// 2034 - A close authority extension authority constraint was violated
163    #[msg("A close authority extension authority constraint was violated")]
164    ConstraintMintCloseAuthorityExtensionAuthority,
165    /// 2035 - A permanent delegate extension constraint was violated
166    #[msg("A permanent delegate extension constraint was violated")]
167    ConstraintMintPermanentDelegateExtension,
168    /// 2036 - A permanent delegate extension authority constraint was violated
169    #[msg("A permanent delegate extension delegate constraint was violated")]
170    ConstraintMintPermanentDelegateExtensionDelegate,
171    /// 2037 - A transfer hook extension constraint was violated
172    #[msg("A transfer hook extension constraint was violated")]
173    ConstraintMintTransferHookExtension,
174    /// 2038 - A transfer hook extension authority constraint was violated
175    #[msg("A transfer hook extension authority constraint was violated")]
176    ConstraintMintTransferHookExtensionAuthority,
177    /// 2039 - A transfer hook extension transfer hook program id constraint was violated
178    #[msg("A transfer hook extension transfer hook program id constraint was violated")]
179    ConstraintMintTransferHookExtensionProgramId,
180
181    // Require
182    /// 2500 - A require expression was violated
183    #[msg("A require expression was violated")]
184    RequireViolated = 2500,
185    /// 2501 - A require_eq expression was violated
186    #[msg("A require_eq expression was violated")]
187    RequireEqViolated,
188    /// 2502 - A require_keys_eq expression was violated
189    #[msg("A require_keys_eq expression was violated")]
190    RequireKeysEqViolated,
191    /// 2503 - A require_neq expression was violated
192    #[msg("A require_neq expression was violated")]
193    RequireNeqViolated,
194    /// 2504 - A require_keys_neq expression was violated
195    #[msg("A require_keys_neq expression was violated")]
196    RequireKeysNeqViolated,
197    /// 2505 - A require_gt expression was violated
198    #[msg("A require_gt expression was violated")]
199    RequireGtViolated,
200    /// 2506 - A require_gte expression was violated
201    #[msg("A require_gte expression was violated")]
202    RequireGteViolated,
203
204    // Accounts.
205    /// 3000 - The account discriminator was already set on this account
206    #[msg("The account discriminator was already set on this account")]
207    AccountDiscriminatorAlreadySet = 3000,
208    /// 3001 - No discriminator was found on the account
209    #[msg("No discriminator was found on the account")]
210    AccountDiscriminatorNotFound,
211    /// 3002 - Account discriminator did not match what was expected
212    #[msg("Account discriminator did not match what was expected")]
213    AccountDiscriminatorMismatch,
214    /// 3003 - Failed to deserialize the account
215    #[msg("Failed to deserialize the account")]
216    AccountDidNotDeserialize,
217    /// 3004 - Failed to serialize the account
218    #[msg("Failed to serialize the account")]
219    AccountDidNotSerialize,
220    /// 3005 - Not enough account keys given to the instruction
221    #[msg("Not enough account keys given to the instruction")]
222    AccountNotEnoughKeys,
223    /// 3006 - The given account is not mutable
224    #[msg("The given account is not mutable")]
225    AccountNotMutable,
226    /// 3007 - The given account is owned by a different program than expected
227    #[msg("The given account is owned by a different program than expected")]
228    AccountOwnedByWrongProgram,
229    /// 3008 - Program ID was not as expected
230    #[msg("Program ID was not as expected")]
231    InvalidProgramId,
232    /// 3009 - Program account is not executable
233    #[msg("Program account is not executable")]
234    InvalidProgramExecutable,
235    /// 3010 - The given account did not sign
236    #[msg("The given account did not sign")]
237    AccountNotSigner,
238    /// 3011 - The given account is not owned by the system program
239    #[msg("The given account is not owned by the system program")]
240    AccountNotSystemOwned,
241    /// 3012 - The program expected this account to be already initialized
242    #[msg("The program expected this account to be already initialized")]
243    AccountNotInitialized,
244    /// 3013 - The given account is not a program data account
245    #[msg("The given account is not a program data account")]
246    AccountNotProgramData,
247    /// 3014 - The given account is not the associated token account
248    #[msg("The given account is not the associated token account")]
249    AccountNotAssociatedTokenAccount,
250    /// 3015 - The given public key does not match the required sysvar
251    #[msg("The given public key does not match the required sysvar")]
252    AccountSysvarMismatch,
253    /// 3016 - The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit
254    #[msg("The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit")]
255    AccountReallocExceedsLimit,
256    /// 3017 - The account was duplicated for more than one reallocation
257    #[msg("The account was duplicated for more than one reallocation")]
258    AccountDuplicateReallocs,
259
260    // Miscellaneous
261    /// 4100 - The declared program id does not match actual program id
262    #[msg("The declared program id does not match the actual program id")]
263    DeclaredProgramIdMismatch = 4100,
264    /// 4101 - You cannot/should not initialize the payer account as a program account
265    #[msg("You cannot/should not initialize the payer account as a program account")]
266    TryingToInitPayerAsProgramAccount = 4101,
267    /// 4102 - Invalid numeric conversion error
268    #[msg("Error during numeric conversion")]
269    InvalidNumericConversion = 4102,
270
271    // Deprecated
272    /// 5000 - The API being used is deprecated and should no longer be used
273    #[msg("The API being used is deprecated and should no longer be used")]
274    Deprecated = 5000,
275}
276
277#[derive(Debug, PartialEq, Eq)]
278pub enum Error {
279    AnchorError(Box<AnchorError>),
280    ProgramError(Box<ProgramErrorWithOrigin>),
281}
282
283impl std::error::Error for Error {}
284
285impl Display for Error {
286    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
287        match self {
288            Error::AnchorError(ae) => Display::fmt(&ae, f),
289            Error::ProgramError(pe) => Display::fmt(&pe, f),
290        }
291    }
292}
293
294impl From<AnchorError> for Error {
295    fn from(ae: AnchorError) -> Self {
296        Self::AnchorError(Box::new(ae))
297    }
298}
299
300impl From<ProgramError> for Error {
301    fn from(program_error: ProgramError) -> Self {
302        Self::ProgramError(Box::new(program_error.into()))
303    }
304}
305impl From<BorshIoError> for Error {
306    fn from(error: BorshIoError) -> Self {
307        Error::ProgramError(Box::new(ProgramError::from(error).into()))
308    }
309}
310
311impl From<ProgramErrorWithOrigin> for Error {
312    fn from(pe: ProgramErrorWithOrigin) -> Self {
313        Self::ProgramError(Box::new(pe))
314    }
315}
316
317impl From<TryFromIntError> for Error {
318    fn from(e: TryFromIntError) -> Self {
319        Self::AnchorError(Box::new(AnchorError {
320            error_name: ErrorCode::InvalidNumericConversion.name(),
321            error_code_number: ErrorCode::InvalidNumericConversion.into(),
322            error_msg: format!("{}", e),
323            error_origin: None,
324            compared_values: None,
325        }))
326    }
327}
328
329impl Error {
330    pub fn log(&self) {
331        match self {
332            Error::ProgramError(program_error) => program_error.log(),
333            Error::AnchorError(anchor_error) => anchor_error.log(),
334        }
335    }
336
337    pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
338        match &mut self {
339            Error::AnchorError(ae) => {
340                ae.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
341            }
342            Error::ProgramError(pe) => {
343                pe.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
344            }
345        };
346        self
347    }
348
349    pub fn with_source(mut self, source: Source) -> Self {
350        match &mut self {
351            Error::AnchorError(ae) => {
352                ae.error_origin = Some(ErrorOrigin::Source(source));
353            }
354            Error::ProgramError(pe) => {
355                pe.error_origin = Some(ErrorOrigin::Source(source));
356            }
357        };
358        self
359    }
360
361    pub fn with_pubkeys(mut self, pubkeys: (Pubkey, Pubkey)) -> Self {
362        let pubkeys = Some(ComparedValues::Pubkeys((pubkeys.0, pubkeys.1)));
363        match &mut self {
364            Error::AnchorError(ae) => ae.compared_values = pubkeys,
365            Error::ProgramError(pe) => pe.compared_values = pubkeys,
366        };
367        self
368    }
369
370    pub fn with_values(mut self, values: (impl ToString, impl ToString)) -> Self {
371        match &mut self {
372            Error::AnchorError(ae) => {
373                ae.compared_values = Some(ComparedValues::Values((
374                    values.0.to_string(),
375                    values.1.to_string(),
376                )))
377            }
378            Error::ProgramError(pe) => {
379                pe.compared_values = Some(ComparedValues::Values((
380                    values.0.to_string(),
381                    values.1.to_string(),
382                )))
383            }
384        };
385        self
386    }
387}
388
389#[derive(Debug)]
390pub struct ProgramErrorWithOrigin {
391    pub program_error: ProgramError,
392    pub error_origin: Option<ErrorOrigin>,
393    pub compared_values: Option<ComparedValues>,
394}
395
396// Two ProgramErrors are equal when they have the same error code
397impl PartialEq for ProgramErrorWithOrigin {
398    fn eq(&self, other: &Self) -> bool {
399        self.program_error == other.program_error
400    }
401}
402impl Eq for ProgramErrorWithOrigin {}
403
404impl Display for ProgramErrorWithOrigin {
405    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
406        Display::fmt(&self.program_error, f)
407    }
408}
409
410impl ProgramErrorWithOrigin {
411    pub fn log(&self) {
412        match &self.error_origin {
413            None => {
414                anchor_lang::solana_program::msg!(
415                    "ProgramError occurred. Error Code: {:?}. Error Number: {}. Error Message: {}.",
416                    self.program_error,
417                    u64::from(self.program_error.clone()),
418                    self.program_error
419                );
420            }
421            Some(ErrorOrigin::Source(source)) => {
422                anchor_lang::solana_program::msg!(
423                    "ProgramError thrown in {}:{}. Error Code: {:?}. Error Number: {}. Error Message: {}.",
424                    source.filename,
425                    source.line,
426                    self.program_error,
427                    u64::from(self.program_error.clone()),
428                    self.program_error
429                );
430            }
431            Some(ErrorOrigin::AccountName(account_name)) => {
432                // using sol_log because msg! wrongly interprets 5 inputs as u64
433                anchor_lang::solana_program::log::sol_log(&format!(
434                    "ProgramError caused by account: {}. Error Code: {:?}. Error Number: {}. Error Message: {}.",
435                    account_name,
436                    self.program_error,
437                    u64::from(self.program_error.clone()),
438                    self.program_error
439                ));
440            }
441        }
442        match &self.compared_values {
443            Some(ComparedValues::Pubkeys((left, right))) => {
444                anchor_lang::solana_program::msg!("Left:");
445                left.log();
446                anchor_lang::solana_program::msg!("Right:");
447                right.log();
448            }
449            Some(ComparedValues::Values((left, right))) => {
450                anchor_lang::solana_program::msg!("Left: {}", left);
451                anchor_lang::solana_program::msg!("Right: {}", right);
452            }
453            None => (),
454        }
455    }
456
457    pub fn with_source(mut self, source: Source) -> Self {
458        self.error_origin = Some(ErrorOrigin::Source(source));
459        self
460    }
461
462    pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
463        self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
464        self
465    }
466}
467
468impl From<ProgramError> for ProgramErrorWithOrigin {
469    fn from(program_error: ProgramError) -> Self {
470        Self {
471            program_error,
472            error_origin: None,
473            compared_values: None,
474        }
475    }
476}
477
478#[derive(Debug)]
479pub enum ComparedValues {
480    Values((String, String)),
481    Pubkeys((Pubkey, Pubkey)),
482}
483
484#[derive(Debug)]
485pub enum ErrorOrigin {
486    Source(Source),
487    AccountName(String),
488}
489
490#[derive(Debug)]
491pub struct AnchorError {
492    pub error_name: String,
493    pub error_code_number: u32,
494    pub error_msg: String,
495    pub error_origin: Option<ErrorOrigin>,
496    pub compared_values: Option<ComparedValues>,
497}
498
499impl AnchorError {
500    pub fn log(&self) {
501        match &self.error_origin {
502            None => {
503                anchor_lang::solana_program::log::sol_log(&format!(
504                    "AnchorError occurred. Error Code: {}. Error Number: {}. Error Message: {}.",
505                    self.error_name, self.error_code_number, self.error_msg
506                ));
507            }
508            Some(ErrorOrigin::Source(source)) => {
509                anchor_lang::solana_program::msg!(
510                    "AnchorError thrown in {}:{}. Error Code: {}. Error Number: {}. Error Message: {}.",
511                    source.filename,
512                    source.line,
513                    self.error_name,
514                    self.error_code_number,
515                    self.error_msg
516                );
517            }
518            Some(ErrorOrigin::AccountName(account_name)) => {
519                anchor_lang::solana_program::log::sol_log(&format!(
520                    "AnchorError caused by account: {}. Error Code: {}. Error Number: {}. Error Message: {}.",
521                    account_name,
522                    self.error_name,
523                    self.error_code_number,
524                    self.error_msg
525                ));
526            }
527        }
528        match &self.compared_values {
529            Some(ComparedValues::Pubkeys((left, right))) => {
530                anchor_lang::solana_program::msg!("Left:");
531                left.log();
532                anchor_lang::solana_program::msg!("Right:");
533                right.log();
534            }
535            Some(ComparedValues::Values((left, right))) => {
536                anchor_lang::solana_program::msg!("Left: {}", left);
537                anchor_lang::solana_program::msg!("Right: {}", right);
538            }
539            None => (),
540        }
541    }
542
543    pub fn with_source(mut self, source: Source) -> Self {
544        self.error_origin = Some(ErrorOrigin::Source(source));
545        self
546    }
547
548    pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
549        self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
550        self
551    }
552}
553
554impl Display for AnchorError {
555    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
556        Debug::fmt(&self, f)
557    }
558}
559
560/// Two `AnchorError`s are equal when they have the same error code
561impl PartialEq for AnchorError {
562    fn eq(&self, other: &Self) -> bool {
563        self.error_code_number == other.error_code_number
564    }
565}
566
567impl Eq for AnchorError {}
568
569impl std::convert::From<Error> for anchor_lang::solana_program::program_error::ProgramError {
570    fn from(e: Error) -> anchor_lang::solana_program::program_error::ProgramError {
571        match e {
572            Error::AnchorError(error) => {
573                anchor_lang::solana_program::program_error::ProgramError::Custom(
574                    error.error_code_number,
575                )
576            }
577            Error::ProgramError(program_error) => program_error.program_error,
578        }
579    }
580}
581
582#[derive(Debug)]
583pub struct Source {
584    pub filename: &'static str,
585    pub line: u32,
586}