confium_daemon/error.rs
1//! Errors surfaced by the confiumd JSON-RPC daemon.
2//!
3//! Daemon errors fall into two layers:
4//! - [`RpcError`] — JSON-RPC protocol errors, serialized into a
5//! `"error"` object on the wire (see `protocol.rs`).
6//! - [`DaemonError`] — transport / lifecycle failures that bubble up to
7//! the listen loop and usually terminate the process.
8
9use snafu::Snafu;
10
11/// JSON-RPC error codes as defined by the spec, plus the
12/// Confium-specific range (−32000 to −32099) for server errors.
13///
14/// Spec: <https://www.jsonrpc.org/specification#error_object>
15pub mod code {
16 /// Invalid JSON was received by the server.
17 pub const PARSE_ERROR: i32 = -32700;
18 /// The JSON sent is not a valid Request object.
19 pub const INVALID_REQUEST: i32 = -32600;
20 /// The method does not exist / is not available.
21 pub const METHOD_NOT_FOUND: i32 = -32601;
22 /// Invalid method parameter(s).
23 pub const INVALID_PARAMS: i32 = -32602;
24 /// Internal JSON-RPC error.
25 pub const INTERNAL_ERROR: i32 = -32603;
26 /// Generic server error (Confium-specific range start).
27 pub const SERVER_ERROR: i32 = -32000;
28 /// A Confium engine operation returned an error.
29 pub const ENGINE_ERROR: i32 = -32001;
30}
31
32/// An error that can be serialized into a JSON-RPC `"error"` object.
33#[derive(Debug, Snafu)]
34#[snafu(visibility(pub))]
35pub enum RpcError {
36 /// The requested method is not registered in the dispatch table.
37 #[snafu(display("Method not found: {method}"))]
38 MethodNotFound { method: String },
39
40 /// The params object was missing required fields or had the wrong
41 /// shape for the method.
42 #[snafu(display("Invalid params: {detail}"))]
43 InvalidParams { detail: String },
44
45 /// The Confium engine returned an error. The message is the
46 /// engine's `Display` string; the numeric sub-code (if the caller
47 /// cares) is logged separately.
48 #[snafu(display("Engine error: {message}"))]
49 Engine { message: String },
50
51 /// Catch-all for unexpected internal failures.
52 #[snafu(display("Internal error: {detail}"))]
53 Internal { detail: String },
54}
55
56impl RpcError {
57 /// Map this error to the JSON-RPC integer code it should be
58 /// reported under.
59 pub fn code(&self) -> i32 {
60 match self {
61 RpcError::MethodNotFound { .. } => code::METHOD_NOT_FOUND,
62 RpcError::InvalidParams { .. } => code::INVALID_PARAMS,
63 RpcError::Engine { .. } => code::ENGINE_ERROR,
64 RpcError::Internal { .. } => code::INTERNAL_ERROR,
65 }
66 }
67}
68
69/// Transport / lifecycle errors that are not reported to the client as
70/// a JSON-RPC error but instead cause the listener or connection loop
71/// to abort.
72#[derive(Debug, Snafu)]
73pub enum DaemonError {
74 #[snafu(display("I/O error: {source}"))]
75 Io { source: std::io::Error },
76
77 #[snafu(display("Failed to serialize response: {source}"))]
78 Serialize { source: serde_json::Error },
79
80 #[snafu(display("Failed to bind listener: {source}"))]
81 Bind { source: std::io::Error },
82
83 #[snafu(display("Shutdown signaled"))]
84 Shutdown,
85}
86
87pub type Result<T> = std::result::Result<T, DaemonError>;
88
89impl From<std::io::Error> for DaemonError {
90 fn from(source: std::io::Error) -> Self {
91 DaemonError::Io { source }
92 }
93}
94
95impl From<serde_json::Error> for DaemonError {
96 fn from(source: serde_json::Error) -> Self {
97 DaemonError::Serialize { source }
98 }
99}