Skip to main content

velesdb_core/
error.rs

1//! Error types for `VelesDB`.
2//!
3//! This module provides a unified error type for all `VelesDB` operations,
4//! designed for professional API exposure to Python/Node clients.
5
6use thiserror::Error;
7
8/// Result type alias for `VelesDB` operations.
9pub type Result<T> = std::result::Result<T, Error>;
10
11/// Errors that can occur in `VelesDB` operations.
12///
13/// Each variant includes a descriptive error message suitable for end-users.
14/// Error codes follow the pattern `VELES-XXX` for easy debugging.
15#[derive(Error, Debug)]
16pub enum Error {
17    /// Collection already exists (VELES-001).
18    #[error("[VELES-001] Collection '{0}' already exists")]
19    CollectionExists(String),
20
21    /// Collection not found (VELES-002).
22    #[error("[VELES-002] Collection '{0}' not found")]
23    CollectionNotFound(String),
24
25    /// Point not found (VELES-003).
26    #[error("[VELES-003] Point with ID '{0}' not found")]
27    PointNotFound(u64),
28
29    /// Dimension mismatch (VELES-004).
30    #[error("[VELES-004] Vector dimension mismatch: expected {expected}, got {actual}")]
31    DimensionMismatch {
32        /// Expected dimension.
33        expected: usize,
34        /// Actual dimension.
35        actual: usize,
36    },
37
38    /// Invalid vector (VELES-005).
39    #[error("[VELES-005] Invalid vector: {0}")]
40    InvalidVector(String),
41
42    /// Storage error (VELES-006).
43    #[error("[VELES-006] Storage error: {0}")]
44    Storage(String),
45
46    /// Index error (VELES-007).
47    #[error("[VELES-007] Index error: {0}")]
48    Index(String),
49
50    /// Index corrupted (VELES-008).
51    ///
52    /// Indicates that index files are corrupted and need to be rebuilt.
53    #[error("[VELES-008] Index corrupted: {0}")]
54    IndexCorrupted(String),
55
56    /// Configuration error (VELES-009).
57    #[error("[VELES-009] Configuration error: {0}")]
58    Config(String),
59
60    /// Query parsing error (VELES-010).
61    ///
62    /// Wraps `VelesQL` parse errors with position and context information.
63    #[error("[VELES-010] Query error: {0}")]
64    Query(String),
65
66    /// IO error (VELES-011).
67    #[error("[VELES-011] IO error: {0}")]
68    Io(#[from] std::io::Error),
69
70    /// Serialization error (VELES-012).
71    #[error("[VELES-012] Serialization error: {0}")]
72    Serialization(String),
73
74    /// Internal error (VELES-013).
75    ///
76    /// Indicates an unexpected internal error. Please report if encountered.
77    #[error("[VELES-013] Internal error: {0}")]
78    Internal(String),
79
80    /// Vector not allowed on metadata-only collection (VELES-014).
81    #[error("[VELES-014] Vector not allowed on metadata-only collection '{0}'")]
82    VectorNotAllowed(String),
83
84    /// Search not supported on metadata-only collection (VELES-015).
85    #[error("[VELES-015] Vector search not supported on metadata-only collection '{0}'. Use query() instead.")]
86    SearchNotSupported(String),
87
88    /// Vector required for vector collection (VELES-016).
89    #[error("[VELES-016] Vector required for collection '{0}' (not metadata-only)")]
90    VectorRequired(String),
91
92    /// Schema validation error (VELES-017).
93    #[error("[VELES-017] Schema validation error: {0}")]
94    SchemaValidation(String),
95
96    /// Graph operation not supported (VELES-018).
97    #[error("[VELES-018] Graph operation not supported: {0}")]
98    GraphNotSupported(String),
99
100    /// Edge already exists (VELES-019).
101    #[error("[VELES-019] Edge with ID '{0}' already exists")]
102    EdgeExists(u64),
103
104    /// Edge not found (VELES-020).
105    #[error("[VELES-020] Edge with ID '{0}' not found")]
106    EdgeNotFound(u64),
107
108    /// Invalid edge label (VELES-021).
109    #[error("[VELES-021] Invalid edge label: {0}")]
110    InvalidEdgeLabel(String),
111
112    /// Node not found (VELES-022).
113    #[error("[VELES-022] Node with ID '{0}' not found")]
114    NodeNotFound(u64),
115
116    /// Numeric overflow (VELES-023).
117    ///
118    /// Indicates a numeric conversion would overflow or truncate.
119    /// Use `try_from()` instead of `as` casts for user-provided data.
120    #[error("[VELES-023] Numeric overflow: {0}")]
121    Overflow(String),
122
123    /// Column store error (VELES-024).
124    ///
125    /// Indicates a column store schema or primary key validation failure.
126    #[error("[VELES-024] Column store error: {0}")]
127    ColumnStoreError(String),
128
129    /// GPU operation error (VELES-025).
130    ///
131    /// Indicates a GPU parameter validation or operation failure.
132    #[error("[VELES-025] GPU error: {0}")]
133    GpuError(String),
134
135    /// Epoch mismatch (VELES-026).
136    ///
137    /// Indicates a stale mmap guard detected after a remap operation.
138    /// This is not recoverable — the guard must be re-acquired.
139    #[error("[VELES-026] Epoch mismatch: {0}")]
140    EpochMismatch(String),
141
142    /// Guard-rail violation (VELES-027).
143    ///
144    /// A query exceeded a configured limit (timeout, depth, cardinality,
145    /// memory, rate limit, or circuit breaker).
146    #[error("[VELES-027] Guard-rail violation: {0}")]
147    GuardRail(String),
148
149    /// Invalid quantizer configuration (VELES-028).
150    ///
151    /// Indicates invalid parameters passed to a quantizer (e.g., empty training set,
152    /// zero subspaces, dimension not divisible by subspaces).
153    #[error("[VELES-028] Invalid quantizer config: {0}")]
154    InvalidQuantizerConfig(String),
155
156    /// Training failed (VELES-029).
157    ///
158    /// Indicates a quantizer training operation failed (convergence, insufficient
159    /// data, etc.).
160    #[error("[VELES-029] Training failed: {0}")]
161    TrainingFailed(String),
162
163    /// Sparse index error (VELES-030).
164    #[error("[VELES-030] Sparse index error: {0}")]
165    SparseIndexError(String),
166}
167
168impl Error {
169    /// Returns the error code (e.g., "VELES-001").
170    #[must_use]
171    pub const fn code(&self) -> &'static str {
172        match self {
173            Self::CollectionExists(_) => "VELES-001",
174            Self::CollectionNotFound(_) => "VELES-002",
175            Self::PointNotFound(_) => "VELES-003",
176            Self::DimensionMismatch { .. } => "VELES-004",
177            Self::InvalidVector(_) => "VELES-005",
178            Self::Storage(_) => "VELES-006",
179            Self::Index(_) => "VELES-007",
180            Self::IndexCorrupted(_) => "VELES-008",
181            Self::Config(_) => "VELES-009",
182            Self::Query(_) => "VELES-010",
183            Self::Io(_) => "VELES-011",
184            Self::Serialization(_) => "VELES-012",
185            Self::Internal(_) => "VELES-013",
186            Self::VectorNotAllowed(_) => "VELES-014",
187            Self::SearchNotSupported(_) => "VELES-015",
188            Self::VectorRequired(_) => "VELES-016",
189            Self::SchemaValidation(_) => "VELES-017",
190            Self::GraphNotSupported(_) => "VELES-018",
191            Self::EdgeExists(_) => "VELES-019",
192            Self::EdgeNotFound(_) => "VELES-020",
193            Self::InvalidEdgeLabel(_) => "VELES-021",
194            Self::NodeNotFound(_) => "VELES-022",
195            Self::Overflow(_) => "VELES-023",
196            Self::ColumnStoreError(_) => "VELES-024",
197            Self::GpuError(_) => "VELES-025",
198            Self::EpochMismatch(_) => "VELES-026",
199            Self::GuardRail(_) => "VELES-027",
200            Self::InvalidQuantizerConfig(_) => "VELES-028",
201            Self::TrainingFailed(_) => "VELES-029",
202            Self::SparseIndexError(_) => "VELES-030",
203        }
204    }
205
206    /// Returns true if this error is recoverable.
207    ///
208    /// Non-recoverable errors include corruption and internal errors.
209    #[must_use]
210    pub const fn is_recoverable(&self) -> bool {
211        !matches!(
212            self,
213            Self::IndexCorrupted(_) | Self::Internal(_) | Self::EpochMismatch(_)
214        )
215    }
216}
217
218/// Conversion from `VelesQL` `ParseError`.
219impl From<crate::velesql::ParseError> for Error {
220    fn from(err: crate::velesql::ParseError) -> Self {
221        Self::Query(err.to_string())
222    }
223}
224
225/// Conversion from `GuardRailViolation` — surfaces limit violations as query errors.
226#[cfg(feature = "persistence")]
227impl From<crate::guardrails::GuardRailViolation> for Error {
228    fn from(v: crate::guardrails::GuardRailViolation) -> Self {
229        Self::GuardRail(v.to_string())
230    }
231}