Skip to main content

anchor_lang/
error.rs

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