1#[derive(Debug, thiserror::Error)]
6pub enum MemoryError {
7 #[error("Database error: {0}")]
9 Database(#[from] rusqlite::Error),
10
11 #[error("Embedding request failed: {0}")]
13 EmbeddingRequest(#[from] reqwest::Error),
14
15 #[cfg(feature = "candle-embedder")]
17 #[error("Candle error: {0}")]
18 CandleError(#[from] candle_core::Error),
19
20 #[error("Embedding provider returned {actual} dimensions, expected {expected}")]
22 DimensionMismatch { expected: usize, actual: usize },
23
24 #[error("Embedding provider returned {returned} vectors, expected {requested}")]
26 EmbeddingBatchCountMismatch { requested: usize, returned: usize },
27
28 #[error("Embedding vector has {actual} dimensions, expected {expected}")]
30 EmbeddingDimensionMismatch { expected: usize, actual: usize },
31
32 #[error("Embedding vector contains non-finite value at index {index}")]
34 NonFiniteEmbeddingValue { index: usize },
35
36 #[error("Vector blob length mismatch: expected {expected_bytes} bytes, got {actual_bytes}")]
38 VectorBlobLengthMismatch {
39 expected_bytes: usize,
40 actual_bytes: usize,
41 },
42
43 #[error("Vector codec profile mismatch: expected {expected_digest}, got {actual_digest}")]
45 VectorCodecProfileMismatch {
46 expected_digest: String,
48 actual_digest: String,
50 },
51
52 #[error("Search receipt ID conflict for {receipt_id}")]
54 SearchReceiptConflict {
55 receipt_id: String,
57 },
58
59 #[error("Digest error: {0}")]
61 DigestError(String),
62
63 #[error("Search receipt not found: {receipt_id}")]
65 SearchReceiptNotFound {
66 receipt_id: String,
68 },
69
70 #[error("Invalid embedding data: expected {expected_bytes} bytes, got {actual_bytes}")]
72 InvalidEmbedding {
73 expected_bytes: usize,
74 actual_bytes: usize,
75 },
76
77 #[error("Embedding model mismatch: database has '{stored}', config specifies '{configured}'")]
79 ModelMismatch { stored: String, configured: String },
80
81 #[error("Session not found: {0}")]
83 SessionNotFound(String),
84
85 #[error("Fact not found: {0}")]
87 FactNotFound(String),
88
89 #[error("Document not found: {0}")]
91 DocumentNotFound(String),
92
93 #[error("Embedding provider unavailable: {0}")]
95 EmbedderUnavailable(String),
96
97 #[error("Migration failed at version {version}: {reason}")]
99 MigrationFailed { version: u32, reason: String },
100
101 #[error("HNSW index error: {0}")]
103 HnswError(String),
104
105 #[error("Not implemented: {0}")]
107 NotImplemented(String),
108
109 #[error("Invalid HNSW key format: {0}")]
111 InvalidKey(String),
112
113 #[error("Quantization error: {0}")]
115 QuantizationError(String),
116
117 #[error("Storage path error: {0}")]
119 StorageError(String),
120
121 #[error("Index integrity check failed: {in_sqlite_not_hnsw} items in SQLite but not HNSW, {in_hnsw_not_sqlite} items in HNSW but not SQLite")]
123 IntegrityError {
124 in_sqlite_not_hnsw: usize,
125 in_hnsw_not_sqlite: usize,
126 },
127
128 #[error(
130 "Schema version {found} is ahead of max supported {supported} — upgrade semantic-memory"
131 )]
132 SchemaAhead {
133 found: u32,
135 supported: u32,
137 },
138
139 #[error("Content too large: {size} bytes exceeds limit of {limit} bytes")]
141 ContentTooLarge {
142 size: usize,
144 limit: usize,
146 },
147
148 #[error("Namespace '{namespace}' has {count} facts, limit is {limit}")]
150 NamespaceFull {
151 namespace: String,
153 count: usize,
155 limit: usize,
157 },
158
159 #[error("Database size limit exceeded: current footprint is {current} bytes, limit is {limit} bytes")]
161 DatabaseSizeLimitExceeded {
162 current: u64,
164 limit: u64,
166 },
167
168 #[error("Episode not found: {0}")]
170 EpisodeNotFound(String),
171
172 #[error("Pool reader acquisition timed out after {elapsed_ms}ms (pool size: {pool_size})")]
174 PoolTimeout {
175 elapsed_ms: u64,
177 pool_size: usize,
179 },
180
181 #[error(
183 "Vector scan hard limit exceeded for {table}: scanned {scanned} rows, limit is {limit}"
184 )]
185 VectorScanLimitExceeded {
186 table: String,
188 scanned: usize,
190 limit: usize,
192 },
193
194 #[error("Invalid configuration for '{field}': {reason}")]
196 InvalidConfig {
197 field: &'static str,
199 reason: String,
201 },
202
203 #[error("Corrupt data in {table} ({row_id}): {detail}")]
205 CorruptData {
206 table: &'static str,
208 row_id: String,
210 detail: String,
212 },
213
214 #[error("Invalid import envelope: {reason}")]
216 ImportInvalid {
217 reason: String,
219 },
220
221 #[error("Import envelope already ingested: {envelope_id}")]
223 ImportDuplicate {
224 envelope_id: String,
226 },
227
228 #[error(
230 "Import requires digest migration or receipt repair for {source_envelope_id}: {detail}"
231 )]
232 ImportMigrationRequired {
233 source_envelope_id: String,
235 detail: String,
237 },
238
239 #[error("authority permit unauthorized for {operation}: principal '{principal}'")]
241 AuthorityUnauthorized {
242 operation: String,
243 principal: String,
244 },
245
246 #[error("authority admission rejected for principal '{principal}': {reason}")]
248 AuthorityAdmissionRejected { principal: String, reason: String },
249
250 #[error("origin authority rejected for principal '{principal}': {reason}")]
252 OriginAuthorityRejected { principal: String, reason: String },
253
254 #[error("authority idempotency conflict for key '{key}'")]
256 AuthorityIdempotencyConflict { key: String },
257
258 #[error("inconsistent authority lineage '{lineage_id}': {detail}")]
260 AuthorityLineageInconsistent { lineage_id: String, detail: String },
261
262 #[error("authority fault injected at stage {stage:?}")]
264 AuthorityFaultInjected {
265 stage: crate::authority_contracts::AuthorityFaultStage,
266 },
267
268 #[error("forgetting closure is incomplete: {detail}")]
270 ForgettingClosureIncomplete { detail: String },
271
272 #[error("forgetting closure budget exceeded: budget {budget}, required at least {required}")]
274 ForgettingBudgetExceeded { budget: usize, required: usize },
275
276 #[error("shadow policy rejected: {reason}")]
278 ShadowPolicyRejected { reason: String },
279
280 #[error("shadow policy proposal not found: {proposal_id}")]
282 ShadowPolicyNotFound { proposal_id: String },
283
284 #[error("shadow policy conflict for key '{key}'")]
286 ShadowPolicyConflict { key: String },
287
288 #[error("shadow policy unauthorized for principal '{principal}'")]
290 ShadowPolicyUnauthorized { principal: String },
291
292 #[error("procedural memory rejected: {reason}")]
294 ProceduralMemoryRejected { reason: String },
295
296 #[error("procedural memory conflict for key '{key}'")]
298 ProceduralMemoryConflict { key: String },
299
300 #[error("procedural memory artifact not found: {artifact_id}")]
302 ProceduralMemoryNotFound { artifact_id: String },
303
304 #[error("procedural memory unauthorized for principal '{principal}'")]
306 ProceduralMemoryUnauthorized { principal: String },
307
308 #[error("{0}")]
310 Other(String),
311}
312
313impl MemoryError {
314 pub fn kind(&self) -> &'static str {
316 match self {
317 Self::Database(_) => "database",
318 Self::EmbeddingRequest(_) => "embedding_request",
319 #[cfg(feature = "candle-embedder")]
320 Self::CandleError(_) => "candle_error",
321 Self::DimensionMismatch { .. } => "dimension_mismatch",
322 Self::EmbeddingBatchCountMismatch { .. } => "embedding_batch_count_mismatch",
323 Self::EmbeddingDimensionMismatch { .. } => "embedding_dimension_mismatch",
324 Self::NonFiniteEmbeddingValue { .. } => "non_finite_embedding_value",
325 Self::VectorBlobLengthMismatch { .. } => "vector_blob_length_mismatch",
326 Self::VectorCodecProfileMismatch { .. } => "vector_codec_profile_mismatch",
327 Self::SearchReceiptConflict { .. } => "search_receipt_conflict",
328 Self::DigestError(_) => "digest_error",
329 Self::SearchReceiptNotFound { .. } => "search_receipt_not_found",
330 Self::InvalidEmbedding { .. } => "invalid_embedding",
331 Self::ModelMismatch { .. } => "model_mismatch",
332 Self::SessionNotFound(_) => "session_not_found",
333 Self::FactNotFound(_) => "fact_not_found",
334 Self::DocumentNotFound(_) => "document_not_found",
335 Self::EpisodeNotFound(_) => "episode_not_found",
336 Self::PoolTimeout { .. } => "pool_timeout",
337 Self::VectorScanLimitExceeded { .. } => "vector_scan_limit_exceeded",
338 Self::EmbedderUnavailable(_) => "embedder_unavailable",
339 Self::MigrationFailed { .. } => "migration_failed",
340 Self::HnswError(_) => "hnsw_error",
341 Self::NotImplemented(_) => "not_implemented",
342 Self::InvalidKey(_) => "invalid_key",
343 Self::QuantizationError(_) => "quantization_error",
344 Self::StorageError(_) => "storage_error",
345 Self::IntegrityError { .. } => "integrity_error",
346 Self::SchemaAhead { .. } => "schema_ahead",
347 Self::ContentTooLarge { .. } => "content_too_large",
348 Self::NamespaceFull { .. } => "namespace_full",
349 Self::DatabaseSizeLimitExceeded { .. } => "database_size_limit_exceeded",
350 Self::InvalidConfig { .. } => "invalid_config",
351 Self::CorruptData { .. } => "corrupt_data",
352 Self::ImportInvalid { .. } => "import_invalid",
353 Self::ImportDuplicate { .. } => "import_duplicate",
354 Self::ImportMigrationRequired { .. } => "import_migration_required",
355 Self::AuthorityUnauthorized { .. } => "authority_unauthorized",
356 Self::AuthorityAdmissionRejected { .. } => "authority_admission_rejected",
357 Self::OriginAuthorityRejected { .. } => "origin_authority_rejected",
358 Self::AuthorityIdempotencyConflict { .. } => "authority_idempotency_conflict",
359 Self::AuthorityLineageInconsistent { .. } => "authority_lineage_inconsistent",
360 Self::AuthorityFaultInjected { .. } => "authority_fault_injected",
361 Self::ForgettingClosureIncomplete { .. } => "forgetting_closure_incomplete",
362 Self::ForgettingBudgetExceeded { .. } => "forgetting_budget_exceeded",
363 Self::ShadowPolicyRejected { .. } => "shadow_policy_rejected",
364 Self::ShadowPolicyNotFound { .. } => "shadow_policy_not_found",
365 Self::ShadowPolicyConflict { .. } => "shadow_policy_conflict",
366 Self::ShadowPolicyUnauthorized { .. } => "shadow_policy_unauthorized",
367 Self::ProceduralMemoryRejected { .. } => "procedural_memory_rejected",
368 Self::ProceduralMemoryConflict { .. } => "procedural_memory_conflict",
369 Self::ProceduralMemoryNotFound { .. } => "procedural_memory_not_found",
370 Self::ProceduralMemoryUnauthorized { .. } => "procedural_memory_unauthorized",
371 Self::Other(_) => "other",
372 }
373 }
374}