Skip to main content

anchor_lang_error/
lib.rs

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