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