kiromi_ai_memory/
error.rs1use std::io;
5
6use crate::partition::{InvalidScheme, PartitionResolveError};
7use crate::tenant::InvalidTenantId;
8
9pub type Result<T, E = Error> = std::result::Result<T, E>;
11
12#[derive(Debug, thiserror::Error)]
14#[non_exhaustive]
15pub enum Error {
16 #[error("storage backend error: {message}")]
18 Storage {
19 message: String,
21 #[source]
22 source: Box<dyn std::error::Error + Send + Sync + 'static>,
24 },
25 #[error("metadata backend error: {message}")]
27 Metadata {
28 message: String,
30 #[source]
31 source: Box<dyn std::error::Error + Send + Sync + 'static>,
33 },
34 #[error("embedder error: {message}")]
36 Embedder {
37 message: String,
39 #[source]
40 source: Box<dyn std::error::Error + Send + Sync + 'static>,
42 },
43 #[error(
45 "embedder mismatch: store has {expected:?} ({expected_dims}d), got {got:?} ({got_dims}d)"
46 )]
47 EmbedderMismatch {
48 expected: String,
50 expected_dims: usize,
52 got: String,
54 got_dims: usize,
56 },
57 #[error("partition scheme mismatch: store has {expected:?}, got {got:?}")]
59 PartitionSchemeMismatch {
60 expected: String,
62 got: String,
64 },
65 #[error("invalid partition: {0}")]
67 PartitionInvalid(#[from] PartitionResolveError),
68 #[error("invalid partition scheme: {0}")]
70 PartitionSchemeInvalid(#[from] InvalidScheme),
71 #[error("invalid tenant id: {0}")]
73 TenantInvalid(#[from] InvalidTenantId),
74 #[error("memory not found: {0}")]
76 MemoryNotFound(String),
77 #[error("summary not found: {0}")]
79 SummaryNotFound(String),
80 #[error("memory is tombstoned: {0}")]
82 Tombstoned(String),
83 #[error("invalid link request: {0}")]
85 LinkInvalid(String),
86 #[error("index corrupt: {0}")]
88 IndexCorrupt(String),
89 #[error("recovery error: {0}")]
91 Recovery(String),
92 #[error("config error: {0}")]
94 Config(String),
95 #[error("capability missing on {plugin}: required={required:?}, got={got:?}")]
98 CapabilityMissing {
99 plugin: &'static str,
101 required: &'static str,
103 got: bool,
105 },
106 #[error("io error: {0}")]
108 Io(#[from] io::Error),
109 #[error("invalid attribute: {reason}")]
113 InvalidAttribute {
114 reason: String,
116 },
117 #[error("invalid anchor: {0}")]
119 InvalidAnchor(String),
120 #[error("snapshot not found: {id}")]
125 SnapshotNotFound {
126 id: String,
128 },
129 #[error("embedder dim mismatch: store has {old}d, got {new}d")]
132 EmbedderDimMismatch {
133 old: usize,
135 new: usize,
137 },
138 #[error("migration conflict: {reason}")]
141 MigrationConflict {
142 reason: String,
144 },
145}
146
147impl Error {
148 pub fn storage<E>(message: impl Into<String>, source: E) -> Self
150 where
151 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
152 {
153 Error::Storage {
154 message: message.into(),
155 source: source.into(),
156 }
157 }
158
159 pub fn metadata<E>(message: impl Into<String>, source: E) -> Self
161 where
162 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
163 {
164 Error::Metadata {
165 message: message.into(),
166 source: source.into(),
167 }
168 }
169
170 pub fn embedder<E>(message: impl Into<String>, source: E) -> Self
172 where
173 E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
174 {
175 Error::Embedder {
176 message: message.into(),
177 source: source.into(),
178 }
179 }
180}
181
182#[cfg(test)]
183mod tests {
184 use super::*;
185
186 #[test]
187 fn display_carries_context() {
188 let e = Error::EmbedderMismatch {
189 expected: "onnx:e5-small:v1".into(),
190 expected_dims: 384,
191 got: "onnx:e5-large:v1".into(),
192 got_dims: 1024,
193 };
194 let s = format!("{e}");
195 assert!(s.contains("e5-small"));
196 assert!(s.contains("384"));
197 assert!(s.contains("e5-large"));
198 }
199
200 #[test]
201 fn from_partition_resolve_error() {
202 let e: Error = PartitionResolveError::MissingKey { key: "user".into() }.into();
203 assert!(matches!(e, Error::PartitionInvalid(_)));
204 }
205}