Skip to main content

ic_query/icrc/model/
error.rs

1//! Module: icrc::model::error
2//!
3//! Responsibility: typed errors for generic ICRC parsing, reports, and live calls.
4//! Does not own: command dispatch, host calls, or output policy.
5//! Boundary: preserves one public error surface for reusable ICRC query behavior.
6
7#[cfg(feature = "host")]
8use crate::runtime::RuntimeError;
9use thiserror::Error as ThisError;
10
11///
12/// IcrcError
13///
14/// Error surfaced by generic ICRC validation, report building, and live calls.
15///
16
17#[derive(Debug, ThisError)]
18pub enum IcrcError {
19    #[cfg(feature = "host")]
20    #[error("failed to create Tokio runtime for ICRC query: {0}")]
21    Runtime(#[from] RuntimeError),
22
23    #[error("failed to build IC agent for endpoint {endpoint}: {reason}")]
24    AgentBuild { endpoint: String, reason: String },
25
26    #[error("invalid {field}: {reason}")]
27    InvalidPrincipal { field: &'static str, reason: String },
28
29    #[error("invalid subaccount hex: {reason}")]
30    InvalidSubaccountHex { reason: String },
31
32    #[error("invalid subaccount length: expected 32 bytes, got {bytes}")]
33    InvalidSubaccountLength { bytes: usize },
34
35    #[error("failed to encode Candid request for {message}: {reason}")]
36    CandidEncode {
37        message: &'static str,
38        reason: String,
39    },
40
41    #[error("ICRC ledger method {method} failed: {reason}")]
42    AgentCall {
43        method: &'static str,
44        reason: String,
45    },
46
47    #[error("failed to decode Candid response {message}: {reason}")]
48    CandidDecode {
49        message: &'static str,
50        reason: String,
51    },
52}
53
54///
55/// IcrcAccountTransactionsError
56///
57/// Error surfaced while resolving and querying an ICRC account index.
58///
59
60#[derive(Debug, ThisError)]
61pub enum IcrcAccountTransactionsError {
62    /// The caller requested an empty page.
63    #[error("invalid ICRC account transaction limit {limit}; expected at least 1")]
64    InvalidLimit {
65        /// Rejected page size.
66        limit: u32,
67    },
68
69    /// A ledger, index, principal, Candid, or transport operation failed.
70    #[error(transparent)]
71    Query(#[from] IcrcError),
72
73    /// ICRC-106 discovery could not be queried or decoded.
74    #[error(
75        "failed to discover an index for ledger {ledger_canister_id}; supply an explicit index canister: {source}"
76    )]
77    IndexDiscovery {
78        /// Ledger queried for index discovery.
79        ledger_canister_id: String,
80        /// Underlying transport or Candid failure.
81        #[source]
82        source: IcrcError,
83    },
84
85    /// ICRC-106 discovery did not yield an index canister.
86    #[error("ledger {ledger_canister_id} has no usable ICRC index: {reason}")]
87    IndexUnavailable {
88        /// Ledger queried for index discovery.
89        ledger_canister_id: String,
90        /// Discovery result explaining why no index is usable.
91        reason: String,
92    },
93
94    /// The selected index reports a different ledger identity.
95    #[error(
96        "ICRC index {index_canister_id} reports ledger {actual_ledger_canister_id}, expected {expected_ledger_canister_id}"
97    )]
98    IndexLedgerMismatch {
99        /// Index whose `ledger_id` response was checked.
100        index_canister_id: String,
101        /// Ledger requested by the caller.
102        expected_ledger_canister_id: String,
103        /// Ledger reported by the index.
104        actual_ledger_canister_id: String,
105    },
106
107    /// The index returned an application-level account-history error.
108    #[error("ICRC index {index_canister_id} account transaction query failed: {message}")]
109    IndexQuery {
110        /// Index that returned the error.
111        index_canister_id: String,
112        /// Index-provided error message.
113        message: String,
114    },
115}