manta_shared/common/error.rs
1//! Structured error type returned by `manta-shared`'s pure helpers.
2//!
3//! Used by the shared `config` loader and re-used by binary-side
4//! helpers that build on it: `manta-cli`'s SAT-file Jinja renderer and
5//! `manta-server`'s `audit`, `jwt_ops`, and `kafka` modules. Lets
6//! `manta-shared` (and therefore `manta-cli`) avoid pulling in
7//! `manta_backend_dispatcher::error::Error` for its own error surface.
8//!
9//! Server-side code keeps returning `manta_backend_dispatcher::error::Error`
10//! and uses `?` to convert `MantaError` at the call site via the
11//! `From<MantaError> for BackendError` impl in
12//! `crates/manta-server/src/wire_conv.rs`.
13
14use thiserror::Error;
15
16/// Errors returned by `manta-shared`'s pure helpers.
17///
18/// Most helpers return `Result<T, MantaError>`. The server-side code
19/// converts these to its richer `BackendError` via
20/// `crates/manta-server/src/wire_conv.rs::to_backend`, which then
21/// maps to HTTP status codes.
22///
23/// # Examples
24///
25/// Pattern-match a NotFound to log a custom message before propagating:
26///
27/// ```
28/// use manta_shared::common::error::MantaError;
29///
30/// fn lookup_thing() -> Result<(), MantaError> {
31/// Err(MantaError::NotFound("thing 42".into()))
32/// }
33///
34/// match lookup_thing() {
35/// Err(MantaError::NotFound(detail)) => {
36/// // Maps to HTTP 404 server-side.
37/// assert_eq!(detail, "thing 42");
38/// }
39/// _ => unreachable!(),
40/// }
41/// ```
42#[derive(Error, Debug)]
43pub enum MantaError {
44 /// Filesystem I/O failure (config-file read, token cache write, etc.).
45 #[error("IO error: {0}")]
46 IoError(#[from] std::io::Error),
47 /// `config` crate failure: bad TOML, env-var parse, or schema
48 /// mismatch on `cli.toml` / `server.toml`.
49 #[error("Config error: {0}")]
50 ConfigError(#[from] config::ConfigError),
51 /// `toml_edit` parse / serialize failure when editing a config
52 /// file in place (e.g. `manta config set`).
53 #[error("TOML edit error: {0}")]
54 TomlEditError(#[from] toml_edit::TomlError),
55 /// JSON serialize / deserialize failure (most often during JWT
56 /// claim extraction or audit payload construction).
57 #[error("Serde error: {0}")]
58 SerdeError(#[from] serde_json::Error),
59 /// `reqwest` failure on outbound HTTP (DNS, TLS handshake, body
60 /// stream, etc.).
61 #[error("Network error: {0}")]
62 NetError(#[from] reqwest::Error),
63 /// YAML parse / serialize failure (SAT-file rendering).
64 #[error("YAML error: {0}")]
65 YamlError(#[from] serde_yaml::Error),
66
67 /// Resource lookup failed (config file missing, group not in
68 /// backend, etc.). Maps to HTTP 404 server-side.
69 #[error("Not found: {0}")]
70 NotFound(String),
71 /// A required field is absent (e.g. JWT lacks `preferred_username`,
72 /// node config lacks `boot_image_id`).
73 #[error("Missing field: {0}")]
74 MissingField(String),
75 /// JWT was structurally invalid (wrong number of dots, undecodable
76 /// claims, non-UTF-8 payload). Maps to HTTP 401.
77 #[error("JWT malformed: {0}")]
78 JwtMalformed(String),
79 /// Kafka producer construction or delivery failed.
80 #[error("Kafka error: {0}")]
81 KafkaError(String),
82 /// User-supplied pattern (hardware pattern, hostlist expression,
83 /// glob) didn't parse. Maps to HTTP 400.
84 #[error("Invalid pattern: {0}")]
85 InvalidPattern(String),
86 /// Jinja2 / minijinja render failed during SAT-file processing.
87 #[error("Template render error: {0}")]
88 TemplateError(String),
89
90 /// Catch-all for messages that don't fit any structured variant.
91 /// Server-side this maps to HTTP 500 — prefer a typed variant when
92 /// adding new failure modes.
93 #[error("{0}")]
94 Other(String),
95}