1use {
2 crate::compat::solana_pubkey::Pubkey,
3 anchor_attribute_error::error_code,
4 solana_program_error::ProgramError,
5 std::{
6 fmt::{Debug, Display},
7 num::TryFromIntError,
8 },
9};
10
11mod compat {
13 #[cfg(all(feature = "solana-v3", feature = "solana-v4"))]
14 compile_error!(
15 "anchor-lang-error: features `solana-v3` and `solana-v4` are mutually exclusive. A \
16 dependency most likely re-enabled default features; pass `default-features = false` \
17 there, or pick a single cohort."
18 );
19 #[cfg(not(any(feature = "solana-v3", feature = "solana-v4")))]
20 compile_error!(
21 "anchor-lang-error: enable exactly one of the `solana-v3` or `solana-v4` features."
22 );
23
24 #[cfg(feature = "solana-v3")]
25 pub(crate) use solana_pubkey_v3 as solana_pubkey;
26 #[cfg(feature = "solana-v4")]
27 pub(crate) use solana_pubkey_v4 as solana_pubkey;
28}
29
30pub const ERROR_CODE_OFFSET: u32 = 6000;
32
33mod anchor_lang {
36 pub(crate) mod error {
37 pub(crate) use crate::{AnchorError, Error};
38 }
39}
40
41#[error_code(offset = 0)]
53pub enum ErrorCode {
54 #[msg("Instruction discriminator not provided")]
57 InstructionMissing = 100,
58 #[msg("Fallback functions are not supported")]
60 InstructionFallbackNotFound,
61 #[msg("The program could not deserialize the given instruction")]
63 InstructionDidNotDeserialize,
64 #[msg("The program could not serialize the given instruction")]
66 InstructionDidNotSerialize,
67
68 #[msg("The program was compiled without idl instructions")]
71 IdlInstructionStub = 1000,
72 #[msg("Invalid program given to the IDL instruction")]
74 IdlInstructionInvalidProgram,
75 #[msg("IDL account must be empty in order to resize, try closing first")]
77 IdlAccountNotEmpty,
78
79 #[msg("The program was compiled without `event-cpi` feature")]
82 EventInstructionStub = 1500,
83
84 #[msg("A mut constraint was violated")]
87 ConstraintMut = 2000,
88 #[msg("A has one constraint was violated")]
90 ConstraintHasOne,
91 #[msg("A signer constraint was violated")]
93 ConstraintSigner,
94 #[msg("A raw constraint was violated")]
96 ConstraintRaw,
97 #[msg("An owner constraint was violated")]
99 ConstraintOwner,
100 #[msg("A rent exemption constraint was violated")]
102 ConstraintRentExempt,
103 #[msg("A seeds constraint was violated")]
105 ConstraintSeeds,
106 #[msg("An executable constraint was violated")]
108 ConstraintExecutable,
109 #[msg("Deprecated Error, feel free to replace with something else")]
111 ConstraintState,
112 #[msg("An associated constraint was violated")]
114 ConstraintAssociated,
115 #[msg("An associated init constraint was violated")]
117 ConstraintAssociatedInit,
118 #[msg("A close constraint was violated")]
120 ConstraintClose,
121 #[msg("An address constraint was violated")]
123 ConstraintAddress,
124 #[msg("Expected zero account discriminant")]
126 ConstraintZero,
127 #[msg("A token mint constraint was violated")]
129 ConstraintTokenMint,
130 #[msg("A token owner constraint was violated")]
132 ConstraintTokenOwner,
133 #[msg("A mint mint authority constraint was violated")]
137 ConstraintMintMintAuthority,
138 #[msg("A mint freeze authority constraint was violated")]
140 ConstraintMintFreezeAuthority,
141 #[msg("A mint decimals constraint was violated")]
143 ConstraintMintDecimals,
144 #[msg("A space constraint was violated")]
146 ConstraintSpace,
147 #[msg("A required account for the constraint is None")]
149 ConstraintAccountIsNone,
150 #[msg("A token account token program constraint was violated")]
154 ConstraintTokenTokenProgram,
155 #[msg("A mint token program constraint was violated")]
157 ConstraintMintTokenProgram,
158 #[msg("An associated token account token program constraint was violated")]
160 ConstraintAssociatedTokenTokenProgram,
161 #[msg("A group pointer extension constraint was violated")]
165 ConstraintMintGroupPointerExtension,
166 #[msg("A group pointer extension authority constraint was violated")]
168 ConstraintMintGroupPointerExtensionAuthority,
169 #[msg("A group pointer extension group address constraint was violated")]
171 ConstraintMintGroupPointerExtensionGroupAddress,
172 #[msg("A group member pointer extension constraint was violated")]
174 ConstraintMintGroupMemberPointerExtension,
175 #[msg("A group member pointer extension authority constraint was violated")]
177 ConstraintMintGroupMemberPointerExtensionAuthority,
178 #[msg("A group member pointer extension group address constraint was violated")]
180 ConstraintMintGroupMemberPointerExtensionMemberAddress,
181 #[msg("A metadata pointer extension constraint was violated")]
183 ConstraintMintMetadataPointerExtension,
184 #[msg("A metadata pointer extension authority constraint was violated")]
186 ConstraintMintMetadataPointerExtensionAuthority,
187 #[msg("A metadata pointer extension metadata address constraint was violated")]
189 ConstraintMintMetadataPointerExtensionMetadataAddress,
190 #[msg("A close authority constraint was violated")]
192 ConstraintMintCloseAuthorityExtension,
193 #[msg("A close authority extension authority constraint was violated")]
195 ConstraintMintCloseAuthorityExtensionAuthority,
196 #[msg("A permanent delegate extension constraint was violated")]
198 ConstraintMintPermanentDelegateExtension,
199 #[msg("A permanent delegate extension delegate constraint was violated")]
201 ConstraintMintPermanentDelegateExtensionDelegate,
202 #[msg("A transfer hook extension constraint was violated")]
204 ConstraintMintTransferHookExtension,
205 #[msg("A transfer hook extension authority constraint was violated")]
207 ConstraintMintTransferHookExtensionAuthority,
208 #[msg("A transfer hook extension transfer hook program id constraint was violated")]
210 ConstraintMintTransferHookExtensionProgramId,
211 #[msg("A duplicate mutable account constraint was violated")]
213 ConstraintDuplicateMutableAccount,
214
215 #[msg("Account is already migrated")]
218 AccountAlreadyMigrated,
219 #[msg("Account must be migrated before exiting")]
221 AccountNotMigrated,
222
223 #[msg("A pausable extension constraint was violated")]
225 ConstraintMintPausableExtension,
226 #[msg("A pausable extension authority constraint was violated")]
228 ConstraintMintPausableAuthority,
229
230 #[msg("A require expression was violated")]
233 RequireViolated = 2500,
234 #[msg("A require_eq expression was violated")]
236 RequireEqViolated,
237 #[msg("A require_keys_eq expression was violated")]
239 RequireKeysEqViolated,
240 #[msg("A require_neq expression was violated")]
242 RequireNeqViolated,
243 #[msg("A require_keys_neq expression was violated")]
245 RequireKeysNeqViolated,
246 #[msg("A require_gt expression was violated")]
248 RequireGtViolated,
249 #[msg("A require_gte expression was violated")]
251 RequireGteViolated,
252
253 #[msg("The account discriminator was already set on this account")]
256 AccountDiscriminatorAlreadySet = 3000,
257 #[msg("No discriminator was found on the account")]
259 AccountDiscriminatorNotFound,
260 #[msg("Account discriminator did not match what was expected")]
262 AccountDiscriminatorMismatch,
263 #[msg("Failed to deserialize the account")]
265 AccountDidNotDeserialize,
266 #[msg("Failed to serialize the account")]
268 AccountDidNotSerialize,
269 #[msg("Not enough account keys given to the instruction")]
271 AccountNotEnoughKeys,
272 #[msg("The given account is not mutable")]
274 AccountNotMutable,
275 #[msg("The given account is owned by a different program than expected")]
277 AccountOwnedByWrongProgram,
278 #[msg("Program ID was not as expected")]
280 InvalidProgramId,
281 #[msg("Program account is not executable")]
283 InvalidProgramExecutable,
284 #[msg("The given account did not sign")]
286 AccountNotSigner,
287 #[msg("The given account is not owned by the system program")]
289 AccountNotSystemOwned,
290 #[msg("The program expected this account to be already initialized")]
292 AccountNotInitialized,
293 #[msg("The given account is not a program data account")]
295 AccountNotProgramData,
296 #[msg("The given account is not the associated token account")]
298 AccountNotAssociatedTokenAccount,
299 #[msg("The given public key does not match the required sysvar")]
301 AccountSysvarMismatch,
302 #[msg("The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit")]
304 AccountReallocExceedsLimit,
305 #[msg("The account was duplicated for more than one reallocation")]
307 AccountDuplicateReallocs,
308
309 #[msg("The declared program id does not match the actual program id")]
312 DeclaredProgramIdMismatch = 4100,
313 #[msg("You cannot/should not initialize the payer account as a program account")]
315 TryingToInitPayerAsProgramAccount = 4101,
316 #[msg("Error during numeric conversion")]
318 InvalidNumericConversion = 4102,
319
320 #[msg("The API being used is deprecated and should no longer be used")]
323 Deprecated = 5000,
324}
325
326#[derive(Debug, PartialEq, Eq)]
327pub enum Error {
328 AnchorError(Box<AnchorError>),
329 ProgramError(Box<ProgramErrorWithOrigin>),
330}
331
332impl std::error::Error for Error {}
333
334impl Display for Error {
335 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
336 match self {
337 Error::AnchorError(ae) => Display::fmt(&ae, f),
338 Error::ProgramError(pe) => Display::fmt(&pe, f),
339 }
340 }
341}
342
343impl From<AnchorError> for Error {
344 fn from(ae: AnchorError) -> Self {
345 Self::AnchorError(Box::new(ae))
346 }
347}
348
349impl From<ProgramError> for Error {
350 fn from(program_error: ProgramError) -> Self {
351 Self::ProgramError(Box::new(program_error.into()))
352 }
353}
354
355#[cfg(feature = "borsh")]
356impl From<borsh::io::Error> for Error {
357 fn from(error: borsh::io::Error) -> Self {
358 Error::ProgramError(Box::new(ProgramError::from(error).into()))
359 }
360}
361
362impl From<ProgramErrorWithOrigin> for Error {
363 fn from(pe: ProgramErrorWithOrigin) -> Self {
364 Self::ProgramError(Box::new(pe))
365 }
366}
367
368impl From<TryFromIntError> for Error {
369 fn from(e: TryFromIntError) -> Self {
370 Self::AnchorError(Box::new(AnchorError {
371 error_name: ErrorCode::InvalidNumericConversion.name(),
372 error_code_number: ErrorCode::InvalidNumericConversion.into(),
373 error_msg: format!("{e}"),
374 error_origin: None,
375 compared_values: None,
376 }))
377 }
378}
379
380impl From<std::convert::Infallible> for Error {
381 fn from(_: std::convert::Infallible) -> Self {
382 unreachable!("Infallible has no inhabitants")
383 }
384}
385
386impl Error {
387 pub fn log(&self) {
388 match self {
389 Error::ProgramError(program_error) => program_error.log(),
390 Error::AnchorError(anchor_error) => anchor_error.log(),
391 }
392 }
393
394 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
395 match &mut self {
396 Error::AnchorError(ae) => {
397 ae.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
398 }
399 Error::ProgramError(pe) => {
400 pe.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
401 }
402 };
403 self
404 }
405
406 pub fn with_source(mut self, source: Source) -> Self {
407 match &mut self {
408 Error::AnchorError(ae) => {
409 ae.error_origin = Some(ErrorOrigin::Source(source));
410 }
411 Error::ProgramError(pe) => {
412 pe.error_origin = Some(ErrorOrigin::Source(source));
413 }
414 };
415 self
416 }
417
418 pub fn with_pubkeys(mut self, pubkeys: (Pubkey, Pubkey)) -> Self {
419 let pubkeys = Some(ComparedValues::Pubkeys((pubkeys.0, pubkeys.1)));
420 match &mut self {
421 Error::AnchorError(ae) => ae.compared_values = pubkeys,
422 Error::ProgramError(pe) => pe.compared_values = pubkeys,
423 };
424 self
425 }
426
427 pub fn with_values(mut self, values: (impl ToString, impl ToString)) -> Self {
428 match &mut self {
429 Error::AnchorError(ae) => {
430 ae.compared_values = Some(ComparedValues::Values((
431 values.0.to_string(),
432 values.1.to_string(),
433 )))
434 }
435 Error::ProgramError(pe) => {
436 pe.compared_values = Some(ComparedValues::Values((
437 values.0.to_string(),
438 values.1.to_string(),
439 )))
440 }
441 };
442 self
443 }
444}
445
446#[derive(Debug)]
447pub struct ProgramErrorWithOrigin {
448 pub program_error: ProgramError,
449 pub error_origin: Option<ErrorOrigin>,
450 pub compared_values: Option<ComparedValues>,
451}
452
453impl PartialEq for ProgramErrorWithOrigin {
455 fn eq(&self, other: &Self) -> bool {
456 self.program_error == other.program_error
457 }
458}
459impl Eq for ProgramErrorWithOrigin {}
460
461impl Display for ProgramErrorWithOrigin {
462 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
463 Display::fmt(&self.program_error, f)
464 }
465}
466
467impl ProgramErrorWithOrigin {
468 pub fn log(&self) {
469 match &self.error_origin {
470 None => {
471 solana_msg::msg!(
472 "ProgramError occurred. Error Code: {:?}. Error Number: {}. Error Message: {}.",
473 self.program_error,
474 u64::from(self.program_error.clone()),
475 self.program_error
476 );
477 }
478 Some(ErrorOrigin::Source(source)) => {
479 solana_msg::msg!(
480 "ProgramError thrown in {}:{}. Error Code: {:?}. Error Number: {}. Error \
481 Message: {}.",
482 source.filename,
483 source.line,
484 self.program_error,
485 u64::from(self.program_error.clone()),
486 self.program_error
487 );
488 }
489 Some(ErrorOrigin::AccountName(account_name)) => {
490 solana_msg::msg!(&format!(
492 "ProgramError caused by account: {}. Error Code: {:?}. Error Number: {}. \
493 Error Message: {}.",
494 account_name,
495 self.program_error,
496 u64::from(self.program_error.clone()),
497 self.program_error
498 ));
499 }
500 }
501 match &self.compared_values {
502 Some(ComparedValues::Pubkeys((left, right))) => {
503 solana_msg::msg!("Left:");
504 left.log();
505 solana_msg::msg!("Right:");
506 right.log();
507 }
508 Some(ComparedValues::Values((left, right))) => {
509 solana_msg::msg!("Left: {}", left);
510 solana_msg::msg!("Right: {}", right);
511 }
512 None => (),
513 }
514 }
515
516 pub fn with_source(mut self, source: Source) -> Self {
517 self.error_origin = Some(ErrorOrigin::Source(source));
518 self
519 }
520
521 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
522 self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
523 self
524 }
525}
526
527impl From<ProgramError> for ProgramErrorWithOrigin {
528 fn from(program_error: ProgramError) -> Self {
529 Self {
530 program_error,
531 error_origin: None,
532 compared_values: None,
533 }
534 }
535}
536
537#[derive(Debug)]
538pub enum ComparedValues {
539 Values((String, String)),
540 Pubkeys((Pubkey, Pubkey)),
541}
542
543#[derive(Debug)]
544pub enum ErrorOrigin {
545 Source(Source),
546 AccountName(String),
547}
548
549#[derive(Debug)]
550pub struct AnchorError {
551 pub error_name: String,
552 pub error_code_number: u32,
553 pub error_msg: String,
554 pub error_origin: Option<ErrorOrigin>,
555 pub compared_values: Option<ComparedValues>,
556}
557
558impl AnchorError {
559 pub fn log(&self) {
560 match &self.error_origin {
561 None => {
562 solana_msg::msg!(
563 "AnchorError occurred. Error Code: {}. Error Number: {}. Error Message: {}.",
564 self.error_name,
565 self.error_code_number,
566 self.error_msg
567 );
568 }
569 Some(ErrorOrigin::Source(source)) => {
570 solana_msg::msg!(
571 "AnchorError thrown in {}:{}. Error Code: {}. Error Number: {}. Error \
572 Message: {}.",
573 source.filename,
574 source.line,
575 self.error_name,
576 self.error_code_number,
577 self.error_msg
578 );
579 }
580 Some(ErrorOrigin::AccountName(account_name)) => {
581 solana_msg::msg!(
582 "AnchorError caused by account: {}. Error Code: {}. Error Number: {}. Error \
583 Message: {}.",
584 account_name,
585 self.error_name,
586 self.error_code_number,
587 self.error_msg
588 );
589 }
590 }
591 match &self.compared_values {
592 Some(ComparedValues::Pubkeys((left, right))) => {
593 solana_msg::msg!("Left:");
594 left.log();
595 solana_msg::msg!("Right:");
596 right.log();
597 }
598 Some(ComparedValues::Values((left, right))) => {
599 solana_msg::msg!("Left: {}", left);
600 solana_msg::msg!("Right: {}", right);
601 }
602 None => (),
603 }
604 }
605
606 pub fn with_source(mut self, source: Source) -> Self {
607 self.error_origin = Some(ErrorOrigin::Source(source));
608 self
609 }
610
611 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
612 self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
613 self
614 }
615}
616
617impl Display for AnchorError {
618 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
619 Debug::fmt(&self, f)
620 }
621}
622
623impl PartialEq for AnchorError {
625 fn eq(&self, other: &Self) -> bool {
626 self.error_code_number == other.error_code_number
627 }
628}
629
630impl Eq for AnchorError {}
631
632impl std::convert::From<Error> for ProgramError {
633 fn from(e: Error) -> ProgramError {
634 match e {
635 Error::AnchorError(error) => ProgramError::Custom(error.error_code_number),
636 Error::ProgramError(program_error) => program_error.program_error,
637 }
638 }
639}
640
641#[derive(Debug)]
642pub struct Source {
643 pub filename: &'static str,
644 pub line: u32,
645}