Skip to main content

systemprompt_models/errors/
core.rs

1//! The legacy [`CoreError`] umbrella enum — a closed set of variants
2//! covering authentication, session, module, and IO failure modes with
3//! HTTP status code mapping helpers.
4
5use systemprompt_identifiers::{SessionId, UserId};
6
7#[derive(Debug, Clone, thiserror::Error)]
8pub enum CoreError {
9    #[error("Module config missing required field: {field}")]
10    MissingConfigField { field: String },
11
12    #[error("Invalid module version: {version}")]
13    InvalidVersion { version: String },
14
15    #[error("Module {name} configuration invalid: {reason}")]
16    InvalidModuleConfig { name: String, reason: String },
17
18    #[error("Module {name} not found")]
19    ModuleNotFound { name: String },
20
21    #[error("Invalid module field {field}: {reason}")]
22    InvalidField { field: String, reason: String },
23
24    #[error("Version comparison failed: {reason}")]
25    VersionComparisonFailed { reason: String },
26
27    #[error("Authentication failed: {reason}")]
28    AuthenticationFailed { reason: String },
29
30    #[error("Invalid or expired token")]
31    InvalidToken,
32
33    #[error("Token expired")]
34    TokenExpired,
35
36    #[error("Invalid token signature")]
37    InvalidSignature,
38
39    #[error("Missing required claim: {claim}")]
40    MissingClaim { claim: String },
41
42    #[error("Invalid authorization header")]
43    InvalidAuthHeader,
44
45    #[error("Invalid token format")]
46    InvalidTokenFormat,
47
48    #[error("Unauthorized")]
49    Unauthorized,
50
51    #[error("Forbidden: {reason}")]
52    Forbidden { reason: String },
53
54    #[error("User not found: {}", user_id.as_str())]
55    UserNotFound { user_id: UserId },
56
57    #[error("Session not found: {}", session_id.as_str())]
58    SessionNotFound { session_id: SessionId },
59
60    #[error("Invalid session: {reason}")]
61    InvalidSession { reason: String },
62
63    #[error("Session expired")]
64    SessionExpired,
65
66    #[error("Cookie not found")]
67    CookieNotFound,
68
69    #[error("Invalid cookie format")]
70    InvalidCookieFormat,
71
72    #[error("Database error: {reason}")]
73    DatabaseError { reason: String },
74
75    #[error("Table not found: {table}")]
76    TableNotFound { table: String },
77
78    #[error("Schema error: {message}")]
79    SchemaError { message: String },
80
81    #[error("File not found: {path}")]
82    FileNotFound { path: String },
83
84    #[error("IO error: {reason}")]
85    IoError { reason: String },
86
87    #[error("Internal server error: {reason}")]
88    InternalError { reason: String },
89}
90
91impl CoreError {
92    #[must_use]
93    pub fn reason(&self) -> String {
94        self.to_string()
95    }
96
97    #[must_use]
98    pub const fn status_code(&self) -> u16 {
99        match self {
100            Self::AuthenticationFailed { .. }
101            | Self::InvalidToken
102            | Self::TokenExpired
103            | Self::InvalidSignature
104            | Self::Unauthorized
105            | Self::SessionExpired => 401,
106            Self::MissingClaim { .. }
107            | Self::InvalidAuthHeader
108            | Self::InvalidTokenFormat
109            | Self::InvalidSession { .. }
110            | Self::CookieNotFound
111            | Self::InvalidCookieFormat
112            | Self::MissingConfigField { .. }
113            | Self::InvalidVersion { .. }
114            | Self::InvalidModuleConfig { .. }
115            | Self::InvalidField { .. }
116            | Self::VersionComparisonFailed { .. } => 400,
117            Self::Forbidden { .. } => 403,
118            Self::UserNotFound { .. }
119            | Self::SessionNotFound { .. }
120            | Self::ModuleNotFound { .. }
121            | Self::TableNotFound { .. }
122            | Self::FileNotFound { .. } => 404,
123            Self::DatabaseError { .. }
124            | Self::SchemaError { .. }
125            | Self::IoError { .. }
126            | Self::InternalError { .. } => 500,
127        }
128    }
129
130    #[must_use]
131    pub const fn is_client_error(&self) -> bool {
132        self.status_code() < 500
133    }
134
135    #[must_use]
136    pub const fn is_server_error(&self) -> bool {
137        self.status_code() >= 500
138    }
139
140    #[must_use]
141    pub const fn is_auth_error(&self) -> bool {
142        matches!(
143            self,
144            Self::AuthenticationFailed { .. }
145                | Self::InvalidToken
146                | Self::TokenExpired
147                | Self::InvalidSignature
148                | Self::InvalidAuthHeader
149                | Self::InvalidTokenFormat
150                | Self::Unauthorized
151                | Self::SessionExpired
152        )
153    }
154
155    #[must_use]
156    pub const fn is_permission_error(&self) -> bool {
157        matches!(self, Self::Forbidden { .. })
158    }
159
160    #[must_use]
161    pub const fn is_not_found(&self) -> bool {
162        matches!(
163            self,
164            Self::UserNotFound { .. }
165                | Self::SessionNotFound { .. }
166                | Self::ModuleNotFound { .. }
167                | Self::TableNotFound { .. }
168                | Self::FileNotFound { .. }
169        )
170    }
171}
172
173impl From<String> for CoreError {
174    fn from(reason: String) -> Self {
175        Self::InternalError { reason }
176    }
177}
178
179impl From<&str> for CoreError {
180    fn from(reason: &str) -> Self {
181        Self::InternalError {
182            reason: reason.to_string(),
183        }
184    }
185}
186
187impl From<std::io::Error> for CoreError {
188    fn from(err: std::io::Error) -> Self {
189        Self::IoError {
190            reason: err.to_string(),
191        }
192    }
193}