Skip to main content

ijima_core/
error.rs

1// Copyright (C) 2026 Industrial Algebra
2// SPDX-License-Identifier: Apache-2.0
3
4//! Centralized error type for the Ijima memory backend.
5
6use thiserror::Error;
7
8/// The single error enum returned by every fallible Ijima operation.
9///
10/// Variants follow the IA convention of carrying structured context
11/// rather than opaque strings, so callers can react to specific failure
12/// modes (a duplicate write, a missing entity, an unrunnable miner).
13#[derive(Debug, Error)]
14pub enum IjimaError {
15    /// A memory write was rejected because equivalent content already
16    /// exists in the palace (content-hash or semantic dedup hit).
17    #[error("duplicate memory rejected: {detail}")]
18    Duplicate {
19        /// Human-readable description of what collided.
20        detail: String,
21    },
22
23    /// A referenced entity, memory, or session was not found.
24    #[error("not found: {detail}")]
25    NotFound {
26        /// What was missing.
27        detail: String,
28    },
29
30    /// The backing store returned an error (SQLite, vector index, file I/O).
31    #[error("store error: {detail}")]
32    Store {
33        /// Underlying store failure description.
34        detail: String,
35    },
36
37    /// A harness-supplied identifier or payload failed validation.
38    #[error("invalid input: {detail}")]
39    InvalidInput {
40        /// Why the input was rejected.
41        detail: String,
42    },
43
44    /// The schema migration/import path failed.
45    #[error("schema error: {detail}")]
46    Schema {
47        /// Migration/import failure description.
48        detail: String,
49    },
50
51    /// The mining engine could not complete an extraction pass.
52    #[error("mining error: {detail}")]
53    Mining {
54        /// Extraction failure description.
55        detail: String,
56    },
57
58    /// A transport-layer failure (HTTP client/server, serialization).
59    #[error("transport error: {detail}")]
60    Transport {
61        /// Transport failure description.
62        detail: String,
63    },
64}
65
66impl IjimaError {
67    /// Construct a [`Duplicate`] error with the given detail string.
68    pub fn duplicate(detail: impl Into<String>) -> Self {
69        Self::Duplicate {
70            detail: detail.into(),
71        }
72    }
73
74    /// Construct a [`NotFound`] error with the given detail string.
75    pub fn not_found(detail: impl Into<String>) -> Self {
76        Self::NotFound {
77            detail: detail.into(),
78        }
79    }
80
81    /// Construct an [`InvalidInput`] error with the given detail string.
82    pub fn invalid_input(detail: impl Into<String>) -> Self {
83        Self::InvalidInput {
84            detail: detail.into(),
85        }
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn duplicate_error_carries_detail() {
95        let err = IjimaError::duplicate("content hash abc123 already present");
96        match err {
97            IjimaError::Duplicate { detail } => {
98                assert_eq!(detail, "content hash abc123 already present");
99            }
100            other => panic!("expected Duplicate, got {other:?}"),
101        }
102    }
103
104    #[test]
105    fn error_display_is_human_readable() {
106        let err = IjimaError::not_found("session sess_42");
107        assert_eq!(err.to_string(), "not found: session sess_42");
108    }
109}