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
11pub const ERROR_CODE_OFFSET: u32 = 6000;
13
14mod anchor_lang {
17 pub(crate) mod error {
18 pub(crate) use crate::{AnchorError, Error};
19 }
20}
21
22#[error_code(offset = 0)]
34pub enum ErrorCode {
35 #[msg("Instruction discriminator not provided")]
38 InstructionMissing = 100,
39 #[msg("Fallback functions are not supported")]
41 InstructionFallbackNotFound,
42 #[msg("The program could not deserialize the given instruction")]
44 InstructionDidNotDeserialize,
45 #[msg("The program could not serialize the given instruction")]
47 InstructionDidNotSerialize,
48
49 #[msg("The program was compiled without idl instructions")]
52 IdlInstructionStub = 1000,
53 #[msg("Invalid program given to the IDL instruction")]
55 IdlInstructionInvalidProgram,
56 #[msg("IDL account must be empty in order to resize, try closing first")]
58 IdlAccountNotEmpty,
59
60 #[msg("The program was compiled without `event-cpi` feature")]
63 EventInstructionStub = 1500,
64
65 #[msg("A mut constraint was violated")]
68 ConstraintMut = 2000,
69 #[msg("A has one constraint was violated")]
71 ConstraintHasOne,
72 #[msg("A signer constraint was violated")]
74 ConstraintSigner,
75 #[msg("A raw constraint was violated")]
77 ConstraintRaw,
78 #[msg("An owner constraint was violated")]
80 ConstraintOwner,
81 #[msg("A rent exemption constraint was violated")]
83 ConstraintRentExempt,
84 #[msg("A seeds constraint was violated")]
86 ConstraintSeeds,
87 #[msg("An executable constraint was violated")]
89 ConstraintExecutable,
90 #[msg("Deprecated Error, feel free to replace with something else")]
92 ConstraintState,
93 #[msg("An associated constraint was violated")]
95 ConstraintAssociated,
96 #[msg("An associated init constraint was violated")]
98 ConstraintAssociatedInit,
99 #[msg("A close constraint was violated")]
101 ConstraintClose,
102 #[msg("An address constraint was violated")]
104 ConstraintAddress,
105 #[msg("Expected zero account discriminant")]
107 ConstraintZero,
108 #[msg("A token mint constraint was violated")]
110 ConstraintTokenMint,
111 #[msg("A token owner constraint was violated")]
113 ConstraintTokenOwner,
114 #[msg("A mint mint authority constraint was violated")]
118 ConstraintMintMintAuthority,
119 #[msg("A mint freeze authority constraint was violated")]
121 ConstraintMintFreezeAuthority,
122 #[msg("A mint decimals constraint was violated")]
124 ConstraintMintDecimals,
125 #[msg("A space constraint was violated")]
127 ConstraintSpace,
128 #[msg("A required account for the constraint is None")]
130 ConstraintAccountIsNone,
131 #[msg("A token account token program constraint was violated")]
135 ConstraintTokenTokenProgram,
136 #[msg("A mint token program constraint was violated")]
138 ConstraintMintTokenProgram,
139 #[msg("An associated token account token program constraint was violated")]
141 ConstraintAssociatedTokenTokenProgram,
142 #[msg("A group pointer extension constraint was violated")]
146 ConstraintMintGroupPointerExtension,
147 #[msg("A group pointer extension authority constraint was violated")]
149 ConstraintMintGroupPointerExtensionAuthority,
150 #[msg("A group pointer extension group address constraint was violated")]
152 ConstraintMintGroupPointerExtensionGroupAddress,
153 #[msg("A group member pointer extension constraint was violated")]
155 ConstraintMintGroupMemberPointerExtension,
156 #[msg("A group member pointer extension authority constraint was violated")]
158 ConstraintMintGroupMemberPointerExtensionAuthority,
159 #[msg("A group member pointer extension group address constraint was violated")]
161 ConstraintMintGroupMemberPointerExtensionMemberAddress,
162 #[msg("A metadata pointer extension constraint was violated")]
164 ConstraintMintMetadataPointerExtension,
165 #[msg("A metadata pointer extension authority constraint was violated")]
167 ConstraintMintMetadataPointerExtensionAuthority,
168 #[msg("A metadata pointer extension metadata address constraint was violated")]
170 ConstraintMintMetadataPointerExtensionMetadataAddress,
171 #[msg("A close authority constraint was violated")]
173 ConstraintMintCloseAuthorityExtension,
174 #[msg("A close authority extension authority constraint was violated")]
176 ConstraintMintCloseAuthorityExtensionAuthority,
177 #[msg("A permanent delegate extension constraint was violated")]
179 ConstraintMintPermanentDelegateExtension,
180 #[msg("A permanent delegate extension delegate constraint was violated")]
182 ConstraintMintPermanentDelegateExtensionDelegate,
183 #[msg("A transfer hook extension constraint was violated")]
185 ConstraintMintTransferHookExtension,
186 #[msg("A transfer hook extension authority constraint was violated")]
188 ConstraintMintTransferHookExtensionAuthority,
189 #[msg("A transfer hook extension transfer hook program id constraint was violated")]
191 ConstraintMintTransferHookExtensionProgramId,
192 #[msg("A duplicate mutable account constraint was violated")]
194 ConstraintDuplicateMutableAccount,
195
196 #[msg("Account is already migrated")]
199 AccountAlreadyMigrated,
200 #[msg("Account must be migrated before exiting")]
202 AccountNotMigrated,
203
204 #[msg("A require expression was violated")]
207 RequireViolated = 2500,
208 #[msg("A require_eq expression was violated")]
210 RequireEqViolated,
211 #[msg("A require_keys_eq expression was violated")]
213 RequireKeysEqViolated,
214 #[msg("A require_neq expression was violated")]
216 RequireNeqViolated,
217 #[msg("A require_keys_neq expression was violated")]
219 RequireKeysNeqViolated,
220 #[msg("A require_gt expression was violated")]
222 RequireGtViolated,
223 #[msg("A require_gte expression was violated")]
225 RequireGteViolated,
226
227 #[msg("The account discriminator was already set on this account")]
230 AccountDiscriminatorAlreadySet = 3000,
231 #[msg("No discriminator was found on the account")]
233 AccountDiscriminatorNotFound,
234 #[msg("Account discriminator did not match what was expected")]
236 AccountDiscriminatorMismatch,
237 #[msg("Failed to deserialize the account")]
239 AccountDidNotDeserialize,
240 #[msg("Failed to serialize the account")]
242 AccountDidNotSerialize,
243 #[msg("Not enough account keys given to the instruction")]
245 AccountNotEnoughKeys,
246 #[msg("The given account is not mutable")]
248 AccountNotMutable,
249 #[msg("The given account is owned by a different program than expected")]
251 AccountOwnedByWrongProgram,
252 #[msg("Program ID was not as expected")]
254 InvalidProgramId,
255 #[msg("Program account is not executable")]
257 InvalidProgramExecutable,
258 #[msg("The given account did not sign")]
260 AccountNotSigner,
261 #[msg("The given account is not owned by the system program")]
263 AccountNotSystemOwned,
264 #[msg("The program expected this account to be already initialized")]
266 AccountNotInitialized,
267 #[msg("The given account is not a program data account")]
269 AccountNotProgramData,
270 #[msg("The given account is not the associated token account")]
272 AccountNotAssociatedTokenAccount,
273 #[msg("The given public key does not match the required sysvar")]
275 AccountSysvarMismatch,
276 #[msg("The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit")]
278 AccountReallocExceedsLimit,
279 #[msg("The account was duplicated for more than one reallocation")]
281 AccountDuplicateReallocs,
282
283 #[msg("The declared program id does not match the actual program id")]
286 DeclaredProgramIdMismatch = 4100,
287 #[msg("You cannot/should not initialize the payer account as a program account")]
289 TryingToInitPayerAsProgramAccount = 4101,
290 #[msg("Error during numeric conversion")]
292 InvalidNumericConversion = 4102,
293
294 #[msg("The API being used is deprecated and should no longer be used")]
297 Deprecated = 5000,
298}
299
300#[derive(Debug, PartialEq, Eq)]
301pub enum Error {
302 AnchorError(Box<AnchorError>),
303 ProgramError(Box<ProgramErrorWithOrigin>),
304}
305
306impl std::error::Error for Error {}
307
308impl Display for Error {
309 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
310 match self {
311 Error::AnchorError(ae) => Display::fmt(&ae, f),
312 Error::ProgramError(pe) => Display::fmt(&pe, f),
313 }
314 }
315}
316
317impl From<AnchorError> for Error {
318 fn from(ae: AnchorError) -> Self {
319 Self::AnchorError(Box::new(ae))
320 }
321}
322
323impl From<ProgramError> for Error {
324 fn from(program_error: ProgramError) -> Self {
325 Self::ProgramError(Box::new(program_error.into()))
326 }
327}
328
329#[cfg(feature = "borsh")]
330impl From<borsh::io::Error> for Error {
331 fn from(error: borsh::io::Error) -> Self {
332 Error::ProgramError(Box::new(ProgramError::from(error).into()))
333 }
334}
335
336impl From<ProgramErrorWithOrigin> for Error {
337 fn from(pe: ProgramErrorWithOrigin) -> Self {
338 Self::ProgramError(Box::new(pe))
339 }
340}
341
342impl From<TryFromIntError> for Error {
343 fn from(e: TryFromIntError) -> Self {
344 Self::AnchorError(Box::new(AnchorError {
345 error_name: ErrorCode::InvalidNumericConversion.name(),
346 error_code_number: ErrorCode::InvalidNumericConversion.into(),
347 error_msg: format!("{e}"),
348 error_origin: None,
349 compared_values: None,
350 }))
351 }
352}
353
354impl From<std::convert::Infallible> for Error {
355 fn from(_: std::convert::Infallible) -> Self {
356 unreachable!("Infallible has no inhabitants")
357 }
358}
359
360impl Error {
361 pub fn log(&self) {
362 match self {
363 Error::ProgramError(program_error) => program_error.log(),
364 Error::AnchorError(anchor_error) => anchor_error.log(),
365 }
366 }
367
368 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
369 match &mut self {
370 Error::AnchorError(ae) => {
371 ae.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
372 }
373 Error::ProgramError(pe) => {
374 pe.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
375 }
376 };
377 self
378 }
379
380 pub fn with_source(mut self, source: Source) -> Self {
381 match &mut self {
382 Error::AnchorError(ae) => {
383 ae.error_origin = Some(ErrorOrigin::Source(source));
384 }
385 Error::ProgramError(pe) => {
386 pe.error_origin = Some(ErrorOrigin::Source(source));
387 }
388 };
389 self
390 }
391
392 pub fn with_pubkeys(mut self, pubkeys: (Pubkey, Pubkey)) -> Self {
393 let pubkeys = Some(ComparedValues::Pubkeys((pubkeys.0, pubkeys.1)));
394 match &mut self {
395 Error::AnchorError(ae) => ae.compared_values = pubkeys,
396 Error::ProgramError(pe) => pe.compared_values = pubkeys,
397 };
398 self
399 }
400
401 pub fn with_values(mut self, values: (impl ToString, impl ToString)) -> Self {
402 match &mut self {
403 Error::AnchorError(ae) => {
404 ae.compared_values = Some(ComparedValues::Values((
405 values.0.to_string(),
406 values.1.to_string(),
407 )))
408 }
409 Error::ProgramError(pe) => {
410 pe.compared_values = Some(ComparedValues::Values((
411 values.0.to_string(),
412 values.1.to_string(),
413 )))
414 }
415 };
416 self
417 }
418}
419
420#[derive(Debug)]
421pub struct ProgramErrorWithOrigin {
422 pub program_error: ProgramError,
423 pub error_origin: Option<ErrorOrigin>,
424 pub compared_values: Option<ComparedValues>,
425}
426
427impl PartialEq for ProgramErrorWithOrigin {
429 fn eq(&self, other: &Self) -> bool {
430 self.program_error == other.program_error
431 }
432}
433impl Eq for ProgramErrorWithOrigin {}
434
435impl Display for ProgramErrorWithOrigin {
436 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
437 Display::fmt(&self.program_error, f)
438 }
439}
440
441impl ProgramErrorWithOrigin {
442 pub fn log(&self) {
443 match &self.error_origin {
444 None => {
445 solana_msg::msg!(
446 "ProgramError occurred. Error Code: {:?}. Error Number: {}. Error Message: {}.",
447 self.program_error,
448 u64::from(self.program_error.clone()),
449 self.program_error
450 );
451 }
452 Some(ErrorOrigin::Source(source)) => {
453 solana_msg::msg!(
454 "ProgramError thrown in {}:{}. Error Code: {:?}. Error Number: {}. Error \
455 Message: {}.",
456 source.filename,
457 source.line,
458 self.program_error,
459 u64::from(self.program_error.clone()),
460 self.program_error
461 );
462 }
463 Some(ErrorOrigin::AccountName(account_name)) => {
464 solana_msg::msg!(&format!(
466 "ProgramError caused by account: {}. Error Code: {:?}. Error Number: {}. \
467 Error Message: {}.",
468 account_name,
469 self.program_error,
470 u64::from(self.program_error.clone()),
471 self.program_error
472 ));
473 }
474 }
475 match &self.compared_values {
476 Some(ComparedValues::Pubkeys((left, right))) => {
477 solana_msg::msg!("Left:");
478 left.log();
479 solana_msg::msg!("Right:");
480 right.log();
481 }
482 Some(ComparedValues::Values((left, right))) => {
483 solana_msg::msg!("Left: {}", left);
484 solana_msg::msg!("Right: {}", right);
485 }
486 None => (),
487 }
488 }
489
490 pub fn with_source(mut self, source: Source) -> Self {
491 self.error_origin = Some(ErrorOrigin::Source(source));
492 self
493 }
494
495 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
496 self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
497 self
498 }
499}
500
501impl From<ProgramError> for ProgramErrorWithOrigin {
502 fn from(program_error: ProgramError) -> Self {
503 Self {
504 program_error,
505 error_origin: None,
506 compared_values: None,
507 }
508 }
509}
510
511#[derive(Debug)]
512pub enum ComparedValues {
513 Values((String, String)),
514 Pubkeys((Pubkey, Pubkey)),
515}
516
517#[derive(Debug)]
518pub enum ErrorOrigin {
519 Source(Source),
520 AccountName(String),
521}
522
523#[derive(Debug)]
524pub struct AnchorError {
525 pub error_name: String,
526 pub error_code_number: u32,
527 pub error_msg: String,
528 pub error_origin: Option<ErrorOrigin>,
529 pub compared_values: Option<ComparedValues>,
530}
531
532impl AnchorError {
533 pub fn log(&self) {
534 match &self.error_origin {
535 None => {
536 solana_msg::msg!(
537 "AnchorError occurred. Error Code: {}. Error Number: {}. Error Message: {}.",
538 self.error_name,
539 self.error_code_number,
540 self.error_msg
541 );
542 }
543 Some(ErrorOrigin::Source(source)) => {
544 solana_msg::msg!(
545 "AnchorError thrown in {}:{}. Error Code: {}. Error Number: {}. Error \
546 Message: {}.",
547 source.filename,
548 source.line,
549 self.error_name,
550 self.error_code_number,
551 self.error_msg
552 );
553 }
554 Some(ErrorOrigin::AccountName(account_name)) => {
555 solana_msg::msg!(
556 "AnchorError caused by account: {}. Error Code: {}. Error Number: {}. Error \
557 Message: {}.",
558 account_name,
559 self.error_name,
560 self.error_code_number,
561 self.error_msg
562 );
563 }
564 }
565 match &self.compared_values {
566 Some(ComparedValues::Pubkeys((left, right))) => {
567 solana_msg::msg!("Left:");
568 left.log();
569 solana_msg::msg!("Right:");
570 right.log();
571 }
572 Some(ComparedValues::Values((left, right))) => {
573 solana_msg::msg!("Left: {}", left);
574 solana_msg::msg!("Right: {}", right);
575 }
576 None => (),
577 }
578 }
579
580 pub fn with_source(mut self, source: Source) -> Self {
581 self.error_origin = Some(ErrorOrigin::Source(source));
582 self
583 }
584
585 pub fn with_account_name(mut self, account_name: impl ToString) -> Self {
586 self.error_origin = Some(ErrorOrigin::AccountName(account_name.to_string()));
587 self
588 }
589}
590
591impl Display for AnchorError {
592 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
593 Debug::fmt(&self, f)
594 }
595}
596
597impl PartialEq for AnchorError {
599 fn eq(&self, other: &Self) -> bool {
600 self.error_code_number == other.error_code_number
601 }
602}
603
604impl Eq for AnchorError {}
605
606impl std::convert::From<Error> for ProgramError {
607 fn from(e: Error) -> ProgramError {
608 match e {
609 Error::AnchorError(error) => ProgramError::Custom(error.error_code_number),
610 Error::ProgramError(program_error) => program_error.program_error,
611 }
612 }
613}
614
615#[derive(Debug)]
616pub struct Source {
617 pub filename: &'static str,
618 pub line: u32,
619}