Skip to main content

ic_query/nns/neuron/report/
error.rs

1//! Module: nns::neuron::report::error
2//!
3//! Responsibility: expose portable and native-wrapper NNS neuron failures.
4//! Does not own: transport execution, cache mechanics, or process presentation.
5//! Boundary: keeps canister and 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/// NnsNeuronError
18///
19/// Portable failure returned while collecting or assembling neuron reports.
20///
21
22#[derive(Debug, ThisError)]
23pub enum NnsNeuronError {
24    /// Shared Governance request, transport, or provenance validation failed.
25    #[error(transparent)]
26    Governance(#[from] NnsGovernanceError),
27
28    /// The requested page size is outside Governance's supported range.
29    #[error("invalid NNS neuron page size {page_size}; expected 1..={max_page_size}")]
30    InvalidPageSize {
31        /// Rejected page size.
32        page_size: u32,
33        /// Largest page supported by Governance.
34        max_page_size: u32,
35    },
36
37    /// Governance returned its typed application-level error.
38    #[error("NNS Governance rejected the neuron query with code {error_type}: {message}")]
39    GovernanceResponse {
40        /// Raw Governance error type.
41        error_type: i32,
42        /// Governance error message.
43        message: String,
44    },
45
46    /// Governance has no publicly readable view for the requested neuron id.
47    #[error("NNS neuron {neuron_id} was not found")]
48    NeuronNotFound {
49        /// Requested neuron identifier.
50        neuron_id: u64,
51    },
52
53    /// Governance returned a neuron row without its required identifier.
54    #[error("NNS Governance returned a neuron row without an id")]
55    MissingNeuronId,
56
57    /// A source page or detail row violated the neuron contract.
58    #[error("invalid NNS neuron response: {reason}")]
59    InvalidResponse {
60        /// Response invariant that failed.
61        reason: String,
62    },
63}
64
65///
66/// NnsNeuronHostError
67///
68/// Native wrapper failure for neuron live calls, caches, and refreshes.
69///
70
71#[cfg(feature = "nns-host")]
72#[derive(Debug, ThisError)]
73pub enum NnsNeuronHostError {
74    /// Portable neuron collection or validation failed.
75    #[error(transparent)]
76    Neuron(#[from] NnsNeuronError),
77
78    /// A capped or stalled refresh stopped before proving API exhaustion.
79    #[error(
80        "NNS neuron refresh stopped after {pages_fetched} pages and {rows_fetched} rows: {reason}"
81    )]
82    IncompleteRefresh {
83        /// Pages retained before the stop.
84        pages_fetched: u32,
85        /// Rows retained before the stop.
86        rows_fetched: usize,
87        /// Completion invariant that failed.
88        reason: String,
89    },
90
91    /// A stored neuron snapshot did not match its cache key.
92    #[error(
93        "cached NNS neuron snapshot identity mismatch at {}: {field} is {actual}, expected {expected}",
94        path.display()
95    )]
96    CacheIdentityMismatch {
97        /// Cache path being validated.
98        path: PathBuf,
99        /// Identity field that did not match.
100        field: &'static str,
101        /// Identity required by the cache key.
102        expected: String,
103        /// Identity stored in the snapshot.
104        actual: String,
105    },
106
107    /// A stored neuron snapshot failed family-specific validation.
108    #[error("invalid NNS neuron cache at {}: {reason}", path.display())]
109    InvalidCache {
110        /// Cache path being validated.
111        path: PathBuf,
112        /// Cache invariant that failed.
113        reason: String,
114    },
115
116    /// A stored refresh-attempt sidecar failed identity or lifecycle validation.
117    #[error("invalid NNS neuron refresh attempt at {}: {reason}", path.display())]
118    InvalidRefreshAttempt {
119        /// Attempt sidecar path being validated.
120        path: PathBuf,
121        /// Attempt invariant that failed.
122        reason: String,
123    },
124
125    /// Shared cache IO or lock handling failed.
126    #[error(transparent)]
127    Cache(#[from] HostCacheError),
128
129    /// The synchronous host runtime could not execute the live query.
130    #[error(transparent)]
131    Runtime(#[from] RuntimeError),
132}
133
134#[cfg(feature = "nns-host")]
135impl From<NnsGovernanceAttemptReadError> for NnsNeuronHostError {
136    fn from(error: NnsGovernanceAttemptReadError) -> Self {
137        match error {
138            NnsGovernanceAttemptReadError::Cache(error) => Self::Cache(error),
139            NnsGovernanceAttemptReadError::Invalid { path, reason } => {
140                Self::InvalidRefreshAttempt { path, reason }
141            }
142        }
143    }
144}