engenho_runtime/error.rs
1//! Typed runtime errors — `thiserror`, no `anyhow` in the lib.
2
3use engenho_apiserver::ServerError;
4use engenho_config::ConfigError;
5use engenho_store::StoreError;
6
7/// Everything that can go wrong booting or shutting down a [`crate::Runtime`].
8#[derive(Debug, thiserror::Error)]
9pub enum RuntimeError {
10 /// Config failed `validate()` or a section was incoherent.
11 #[error("config error: {0}")]
12 Config(#[from] ConfigError),
13
14 /// The store mesh failed to start, initialize, or take leadership.
15 #[error("store error: {0}")]
16 Store(#[from] StoreError),
17
18 /// The apiserver failed to bind or serve.
19 #[error("apiserver error: {0}")]
20 Server(#[from] ServerError),
21
22 /// Raft leadership wasn't reached within the configured timeout.
23 /// The store started but never elected a leader, so no `propose`
24 /// (Node registration, apiserver writes) could ever succeed.
25 #[error("store did not reach leadership within {seconds}s")]
26 LeadershipTimeout {
27 /// The configured leadership timeout that elapsed.
28 seconds: u32,
29 },
30
31 /// `listen_addr` couldn't be parsed into a `SocketAddr`.
32 #[error("invalid listen_addr {addr:?}: {source}")]
33 ListenAddr {
34 /// The unparseable address string.
35 addr: String,
36 /// The parse error.
37 #[source]
38 source: std::net::AddrParseError,
39 },
40
41 /// At shutdown, the Runtime could not become the sole owner of the
42 /// store `Arc` (a driver task or apiserver handler still holds a
43 /// clone). `terminate` consumes `StoreMesh` and requires the only
44 /// strong ref; this surfaces the leak rather than hanging.
45 #[error(
46 "could not acquire sole store ownership for terminate ({strong_count} strong refs remain)"
47 )]
48 StoreStillShared {
49 /// How many strong refs remained when `try_unwrap` failed.
50 strong_count: usize,
51 },
52
53 /// Failed to build or persist the boot-time kubeconfig
54 /// (`data_dir/kubeconfig`). Carries the emitter / io message.
55 #[error("kubeconfig emission failed: {0}")]
56 Kubeconfig(String),
57
58 /// A filesystem operation while writing the kubeconfig failed.
59 #[error("kubeconfig io error at {path}: {source}")]
60 KubeconfigIo {
61 /// The path the operation targeted.
62 path: std::path::PathBuf,
63 /// The underlying io error.
64 #[source]
65 source: std::io::Error,
66 },
67}
68
69engenho_substrate::impl_error_kind! {
70 RuntimeError {
71 (Config(_)) => "config",
72 (Store(_)) => "store",
73 (Server(_)) => "server",
74 { LeadershipTimeout { .. } } => "leadership_timeout",
75 { ListenAddr { .. } } => "listen_addr",
76 { StoreStillShared { .. } } => "store_still_shared",
77 (Kubeconfig(_)) => "kubeconfig",
78 { KubeconfigIo { .. } } => "kubeconfig_io",
79 }
80}