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    Consolidation(ConsolidateError),
36}
37
38impl fmt::Display for CoreError {
39    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
40        match self {
41            Self::ConfigNotFound => {
42                write!(formatter, "[6001] config not found")
43            }
44            Self::ConfigParseError(message) => {
45                write!(formatter, "[6002] config parse error: {message}")
46            }
47            Self::InvalidProvider(message) => {
48                write!(formatter, "[6003] invalid provider: {message}")
49            }
50            Self::IndexCorrupted(message) => {
51                write!(formatter, "[6004] index corrupted: {message}")
52            }
53            Self::RebuildFailed(message) => {
54                write!(formatter, "[6005] rebuild failed: {message}")
55            }
56            Self::SocketError(message) => {
57                write!(formatter, "[6006] socket error: {message}")
58            }
59            Self::DispatchError(message) => {
60                write!(formatter, "[6007] dispatch error: {message}")
61            }
62            Self::ConfigReadOnly => {
63                write!(formatter, "[6008] config is read-only")
64            }
65            Self::ExportFailed(message) => {
66                write!(formatter, "[6009] export failed: {message}")
67            }
68            Self::ImportVersionMismatch(version) => {
69                write!(
70                    formatter,
71                    "[6010] import version mismatch: expected 1, got {version}"
72                )
73            }
74            Self::ImportFailed(message) => {
75                write!(formatter, "[6011] import failed: {message}")
76            }
77            Self::InitFailed(message) => {
78                write!(formatter, "[6012] init failed: {message}")
79            }
80            Self::TrainerFailed(message) => {
81                write!(formatter, "[6013] trainer failed: {message}")
82            }
83            Self::TrainerTimeout => {
84                write!(formatter, "[6014] trainer timeout")
85            }
86            Self::TrainerMalformedOutput(message) => {
87                write!(formatter, "[6015] trainer malformed output: {message}")
88            }
89            Self::ProjectDirNotFound => {
90                write!(
91                    formatter,
92                    "[6016] project directory not found: no .engram/ in cwd or ancestors (run 'engram init')"
93                )
94            }
95            Self::LegacyDatabaseDetected {
96                legacy_path,
97                project_path,
98            } => {
99                write!(
100                    formatter,
101                    "[6017] legacy global database detected at {legacy_path}. Run `engram migrate` to import into project {project_path}, or `engram init` to start fresh."
102                )
103            }
104            Self::MigrationSourceNotFound => {
105                write!(
106                    formatter,
107                    "[6018] migration source not found: no legacy database at ~/.engram/engram.db (nothing to migrate)"
108                )
109            }
110            Self::MigrationFailed(message) => {
111                write!(formatter, "[6019] migration failed: {message}")
112            }
113            Self::Storage(error) => error.fmt(formatter),
114            Self::Hnsw(error) => error.fmt(formatter),
115            Self::Api(error) => error.fmt(formatter),
116            Self::Consolidation(error) => error.fmt(formatter),
117        }
118    }
119}
120
121impl std::error::Error for CoreError {
122    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
123        match self {
124            Self::Storage(error) => Some(error),
125            Self::Hnsw(error) => Some(error),
126            Self::Api(error) => Some(error),
127            Self::Consolidation(error) => Some(error),
128            _ => None,
129        }
130    }
131}
132
133impl From<StorageError> for CoreError {
134    fn from(error: StorageError) -> Self {
135        Self::Storage(error)
136    }
137}
138
139impl From<HnswError> for CoreError {
140    fn from(error: HnswError) -> Self {
141        Self::Hnsw(error)
142    }
143}
144
145impl From<ApiError> for CoreError {
146    fn from(error: ApiError) -> Self {
147        Self::Api(error)
148    }
149}
150
151impl From<ConsolidateError> for CoreError {
152    fn from(error: ConsolidateError) -> Self {
153        Self::Consolidation(error)
154    }
155}