Skip to main content

engram_core/
error.rs

1use std::fmt;
2
3use engram_consolidate::ConsolidateError;
4use engram_hnsw::HnswError;
5use engram_llm_client::ApiError;
6use engram_storage::StorageError;
7
8#[derive(Debug)]
9pub enum CoreError {
10    ConfigNotFound,
11    ConfigParseError(String),
12    InvalidProvider(String),
13    IndexCorrupted(String),
14    RebuildFailed(String),
15    SocketError(String),
16    DispatchError(String),
17    ConfigReadOnly,
18    ExportFailed(String),
19    ImportVersionMismatch(u64),
20    ImportFailed(String),
21    InitFailed(String),
22    Storage(StorageError),
23    Hnsw(HnswError),
24    Api(ApiError),
25    TrainerFailed(String),
26    TrainerTimeout,
27    TrainerMalformedOutput(String),
28    ProjectDirNotFound,
29    LegacyDatabaseDetected {
30        legacy_path: String,
31        project_path: String,
32    },
33    MigrationSourceNotFound,
34    MigrationFailed(String),
35    EmbeddingModelMismatch {
36        stored: String,
37        configured: String,
38    },
39    Consolidation(ConsolidateError),
40}
41
42impl fmt::Display for CoreError {
43    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
44        match self {
45            Self::ConfigNotFound => {
46                write!(formatter, "[6001] config not found")
47            }
48            Self::ConfigParseError(message) => {
49                write!(formatter, "[6002] config parse error: {message}")
50            }
51            Self::InvalidProvider(message) => {
52                write!(formatter, "[6003] invalid provider: {message}")
53            }
54            Self::IndexCorrupted(message) => {
55                write!(formatter, "[6004] index corrupted: {message}")
56            }
57            Self::RebuildFailed(message) => {
58                write!(formatter, "[6005] rebuild failed: {message}")
59            }
60            Self::SocketError(message) => {
61                write!(formatter, "[6006] socket error: {message}")
62            }
63            Self::DispatchError(message) => {
64                write!(formatter, "[6007] dispatch error: {message}")
65            }
66            Self::ConfigReadOnly => {
67                write!(formatter, "[6008] config is read-only")
68            }
69            Self::ExportFailed(message) => {
70                write!(formatter, "[6009] export failed: {message}")
71            }
72            Self::ImportVersionMismatch(version) => {
73                write!(
74                    formatter,
75                    "[6010] import version mismatch: expected 1, got {version}"
76                )
77            }
78            Self::ImportFailed(message) => {
79                write!(formatter, "[6011] import failed: {message}")
80            }
81            Self::InitFailed(message) => {
82                write!(formatter, "[6012] init failed: {message}")
83            }
84            Self::TrainerFailed(message) => {
85                write!(formatter, "[6013] trainer failed: {message}")
86            }
87            Self::TrainerTimeout => {
88                write!(formatter, "[6014] trainer timeout")
89            }
90            Self::TrainerMalformedOutput(message) => {
91                write!(formatter, "[6015] trainer malformed output: {message}")
92            }
93            Self::ProjectDirNotFound => {
94                write!(
95                    formatter,
96                    "[6016] project directory not found: no .engram/ in cwd or ancestors (run 'engram init')"
97                )
98            }
99            Self::LegacyDatabaseDetected {
100                legacy_path,
101                project_path,
102            } => {
103                write!(
104                    formatter,
105                    "[6017] legacy global database detected at {legacy_path}. Run `engram migrate` to import into project {project_path}, or `engram init` to start fresh."
106                )
107            }
108            Self::MigrationSourceNotFound => {
109                write!(
110                    formatter,
111                    "[6018] migration source not found: no legacy database at ~/.engram/engram.db (nothing to migrate)"
112                )
113            }
114            Self::MigrationFailed(message) => {
115                write!(formatter, "[6019] migration failed: {message}")
116            }
117            Self::EmbeddingModelMismatch { stored, configured } => {
118                write!(
119                    formatter,
120                    "[6020] embedding model mismatch: database was last embedded with `{stored}`, but config specifies `{configured}`. Run `engram reembed` to re-compute embeddings, then restart the daemon."
121                )
122            }
123            Self::Storage(error) => error.fmt(formatter),
124            Self::Hnsw(error) => error.fmt(formatter),
125            Self::Api(error) => error.fmt(formatter),
126            Self::Consolidation(error) => error.fmt(formatter),
127        }
128    }
129}
130
131impl std::error::Error for CoreError {
132    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
133        match self {
134            Self::Storage(error) => Some(error),
135            Self::Hnsw(error) => Some(error),
136            Self::Api(error) => Some(error),
137            Self::Consolidation(error) => Some(error),
138            _ => None,
139        }
140    }
141}
142
143impl From<StorageError> for CoreError {
144    fn from(error: StorageError) -> Self {
145        Self::Storage(error)
146    }
147}
148
149impl From<HnswError> for CoreError {
150    fn from(error: HnswError) -> Self {
151        Self::Hnsw(error)
152    }
153}
154
155impl From<ApiError> for CoreError {
156    fn from(error: ApiError) -> Self {
157        Self::Api(error)
158    }
159}
160
161impl From<ConsolidateError> for CoreError {
162    fn from(error: ConsolidateError) -> Self {
163        Self::Consolidation(error)
164    }
165}