Skip to main content

ic_query/nns/proposals/report/
error.rs

1//! Module: nns::proposals::report::error
2//!
3//! Responsibility: expose portable and native-wrapper NNS proposal failures.
4//! Does not own: transport execution, cache mechanics, or process presentation.
5//! Boundary: keeps canister/custom callers independent of native host dependencies.
6
7use crate::nns::governance::NnsGovernanceError;
8#[cfg(feature = "nns-host")]
9use crate::{
10    HostCacheError, nns::governance::NnsGovernanceAttemptReadError, runtime::RuntimeError,
11};
12#[cfg(feature = "nns-host")]
13use std::path::PathBuf;
14use thiserror::Error as ThisError;
15
16///
17/// NnsProposalError
18///
19/// Portable failure returned while collecting or assembling proposal reports.
20///
21
22#[derive(Debug, ThisError)]
23pub enum NnsProposalError {
24    /// Shared Governance request, transport, or provenance validation failed.
25    #[error(transparent)]
26    Governance(#[from] NnsGovernanceError),
27
28    /// The requested page size is outside the bounded proposal contract.
29    #[error("invalid NNS proposal page limit {limit}; expected 1..={maximum}")]
30    InvalidLimit { limit: u32, maximum: u32 },
31
32    /// Governance returned more proposal rows than requested.
33    #[error("NNS proposal page returned {actual} rows; requested at most {requested}")]
34    PageTooLarge { actual: usize, requested: u32 },
35
36    /// A proposal page row did not include its required identifier.
37    #[error("NNS proposal list page returned a row without a proposal id")]
38    MissingProposalIdInPage,
39
40    /// A proposal page repeated an identifier.
41    #[error("NNS proposal page returned duplicate proposal id {proposal_id}")]
42    DuplicateProposalId { proposal_id: u64 },
43
44    /// A proposal did not satisfy the exclusive page cursor.
45    #[error(
46        "NNS proposal page returned id {proposal_id}; expected every id below {before_proposal_id}"
47    )]
48    ProposalCursorMismatch {
49        proposal_id: u64,
50        before_proposal_id: u64,
51    },
52
53    /// Governance did not return the requested proposal.
54    #[error("NNS proposal {proposal_id} was not found")]
55    ProposalNotFound { proposal_id: u64 },
56
57    /// Governance returned a different proposal than requested.
58    #[error("NNS proposal detail returned id {actual:?}; expected {expected}")]
59    ProposalIdMismatch { expected: u64, actual: Option<u64> },
60}
61
62///
63/// NnsProposalHostError
64///
65/// Native wrapper failure for proposal live calls, caches, and refreshes.
66///
67
68#[cfg(feature = "nns-host")]
69#[derive(Debug, ThisError)]
70pub enum NnsProposalHostError {
71    /// Portable proposal collection or validation failed.
72    #[error(transparent)]
73    Proposal(#[from] NnsProposalError),
74
75    #[error(transparent)]
76    Cache(#[from] HostCacheError),
77
78    #[error(
79        "cached NNS proposal snapshot identity mismatch at {}: {field} is {actual}, expected {expected}",
80        path.display()
81    )]
82    CacheIdentityMismatch {
83        path: PathBuf,
84        field: &'static str,
85        expected: String,
86        actual: String,
87    },
88
89    #[error(
90        "NNS proposal refresh did not publish a complete snapshot after {pages_fetched} pages and {rows_fetched} rows: {reason}"
91    )]
92    IncompleteRefresh {
93        pages_fetched: u32,
94        rows_fetched: usize,
95        reason: String,
96    },
97
98    #[error("invalid NNS proposal refresh page size {page_size}; expected 1..={max_page_size}")]
99    InvalidRefreshPageSize { page_size: u32, max_page_size: u32 },
100
101    #[error("NNS proposals cache is missing at {}\n\nRun `icq nns proposal refresh` to fetch a complete snapshot.", path.display())]
102    MissingProposalCache { path: PathBuf },
103
104    #[error("invalid NNS proposal refresh attempt at {}: {reason}", path.display())]
105    InvalidRefreshAttempt { path: PathBuf, reason: String },
106
107    #[error("invalid NNS proposal cache at {}: {reason}", path.display())]
108    InvalidCache { path: PathBuf, reason: String },
109
110    #[error("failed to create Tokio runtime for NNS proposal query: {0}")]
111    Runtime(#[from] RuntimeError),
112}
113
114#[cfg(feature = "nns-host")]
115impl From<NnsGovernanceAttemptReadError> for NnsProposalHostError {
116    fn from(error: NnsGovernanceAttemptReadError) -> Self {
117        match error {
118            NnsGovernanceAttemptReadError::Cache(error) => Self::Cache(error),
119            NnsGovernanceAttemptReadError::Invalid { path, reason } => {
120                Self::InvalidRefreshAttempt { path, reason }
121            }
122        }
123    }
124}