Skip to main content

claw_vector/
error.rs

1// error.rs — VectorError enum (thiserror) + VectorResult<T> + From<VectorError> for tonic::Status.
2use thiserror::Error;
3
4/// Unified error type for all claw-vector operations.
5#[derive(Debug, Error)]
6pub enum VectorError {
7    /// HNSW or flat index failure.
8    #[error("index error: {0}")]
9    Index(String),
10
11    /// SQLite persistence failure.
12    #[error("store error: {0}")]
13    Store(Box<sqlx::Error>),
14
15    /// Embedding generation failure.
16    #[error("embedding error: {0}")]
17    Embedding(String),
18
19    /// gRPC transport failure.
20    #[error("gRPC error: {0}")]
21    Grpc(Box<tonic::Status>),
22
23    /// A collection-level error (not found, already exists, etc.).
24    #[error("collection '{name}': {reason}")]
25    Collection {
26        /// Name of the collection involved.
27        name: String,
28        /// Human-readable explanation.
29        reason: String,
30    },
31
32    /// Vector dimension does not match the collection's configured dimension.
33    #[error("dimension mismatch: expected {expected}, got {got}")]
34    DimensionMismatch {
35        /// Dimension required by the collection.
36        expected: usize,
37        /// Dimension of the supplied vector.
38        got: usize,
39    },
40
41    /// JSON serialisation/deserialisation failure.
42    #[error("serialization error: {0}")]
43    Serialization(Box<serde_json::Error>),
44
45    /// I/O error (file system operations).
46    #[error("io error: {0}")]
47    Io(Box<std::io::Error>),
48
49    /// Invalid configuration.
50    #[error("config error: {0}")]
51    Config(String),
52
53    /// ANN search failure.
54    #[error("search error: {0}")]
55    SearchError(String),
56
57    /// Metadata filter DSL error.
58    #[error("filter error: {0}")]
59    FilterError(String),
60
61    /// The requested entity was not found.
62    #[error("{entity} with id '{id}' not found")]
63    NotFound {
64        /// Type of entity (e.g. "record", "collection").
65        entity: String,
66        /// Identifier that was looked up.
67        id: String,
68    },
69}
70
71impl VectorError {
72    /// Return `true` if this error represents a "not found" condition.
73    pub fn is_not_found(&self) -> bool {
74        matches!(self, VectorError::NotFound { .. })
75    }
76
77    /// Return `true` if this error is a dimension mismatch.
78    pub fn is_dimension_mismatch(&self) -> bool {
79        matches!(self, VectorError::DimensionMismatch { .. })
80    }
81
82    /// Return `true` if this error is a collection-level error.
83    pub fn is_collection_error(&self) -> bool {
84        matches!(self, VectorError::Collection { .. })
85    }
86}
87
88impl From<sqlx::Error> for VectorError {
89    fn from(value: sqlx::Error) -> Self {
90        VectorError::Store(Box::new(value))
91    }
92}
93
94impl From<tonic::Status> for VectorError {
95    fn from(value: tonic::Status) -> Self {
96        VectorError::Grpc(Box::new(value))
97    }
98}
99
100impl From<serde_json::Error> for VectorError {
101    fn from(value: serde_json::Error) -> Self {
102        VectorError::Serialization(Box::new(value))
103    }
104}
105
106impl From<std::io::Error> for VectorError {
107    fn from(value: std::io::Error) -> Self {
108        VectorError::Io(Box::new(value))
109    }
110}
111
112impl From<VectorError> for tonic::Status {
113    fn from(e: VectorError) -> tonic::Status {
114        match &e {
115            VectorError::NotFound { entity, id } => {
116                tonic::Status::not_found(format!("{entity} '{id}' not found"))
117            }
118            VectorError::DimensionMismatch { expected, got } => tonic::Status::invalid_argument(
119                format!("dimension mismatch: expected {expected}, got {got}"),
120            ),
121            VectorError::Collection { name, reason } => {
122                tonic::Status::invalid_argument(format!("collection '{name}': {reason}"))
123            }
124            VectorError::Config(msg) => tonic::Status::invalid_argument(msg.clone()),
125            VectorError::Embedding(msg) => tonic::Status::internal(msg.clone()),
126            VectorError::Index(msg) => tonic::Status::internal(msg.clone()),
127            VectorError::SearchError(msg) => tonic::Status::internal(msg.clone()),
128            VectorError::FilterError(msg) => tonic::Status::internal(msg.clone()),
129            VectorError::Grpc(status) => status.as_ref().clone(),
130            _ => tonic::Status::internal(e.to_string()),
131        }
132    }
133}
134
135/// Convenience result alias used throughout claw-vector.
136pub type VectorResult<T> = Result<T, VectorError>;