Skip to main content

vgi_rpc/
errors.rs

1//! Error types used throughout the vgi-rpc framework.
2
3use std::fmt;
4
5/// An RPC-level error, serialized on the wire as an EXCEPTION log batch.
6#[derive(Debug, Clone)]
7pub struct RpcError {
8    /// Error category (matches Python exception class names: "ValueError",
9    /// "RuntimeError", "TypeError", "ProtocolError", "VersionError", ...).
10    pub error_type: String,
11    /// Human-readable error message.
12    pub message: String,
13    /// Optional stack trace or remote traceback string.
14    pub traceback: String,
15    /// Optional request ID attached when the error was produced.
16    pub request_id: String,
17}
18
19impl RpcError {
20    pub fn new(error_type: impl Into<String>, message: impl Into<String>) -> Self {
21        Self {
22            error_type: error_type.into(),
23            message: message.into(),
24            traceback: String::new(),
25            request_id: String::new(),
26        }
27    }
28
29    pub fn value_error(msg: impl Into<String>) -> Self {
30        Self::new("ValueError", msg)
31    }
32
33    pub fn runtime_error(msg: impl Into<String>) -> Self {
34        Self::new("RuntimeError", msg)
35    }
36
37    pub fn type_error(msg: impl Into<String>) -> Self {
38        Self::new("TypeError", msg)
39    }
40
41    pub fn protocol_error(msg: impl Into<String>) -> Self {
42        Self::new("ProtocolError", msg)
43    }
44
45    pub fn version_error(msg: impl Into<String>) -> Self {
46        Self::new("VersionError", msg)
47    }
48
49    pub fn permission_error(msg: impl Into<String>) -> Self {
50        Self::new("PermissionError", msg)
51    }
52
53    pub fn attribute_error(msg: impl Into<String>) -> Self {
54        Self::new("AttributeError", msg)
55    }
56
57    /// Sticky-session token did not resolve to a live registry entry
58    /// (missing, expired, evicted, wrong worker, or principal mismatch).
59    /// Mirrors Python's `vgi_rpc.rpc.SessionLostError`.
60    pub fn session_lost_error(msg: impl Into<String>) -> Self {
61        Self::new("SessionLostError", msg)
62    }
63
64    /// Server is draining: new `ctx.open_session` calls are rejected while
65    /// existing sessions continue to serve. Mirrors Python's
66    /// `vgi_rpc.rpc.ServerDrainingError`.
67    pub fn server_draining_error(msg: impl Into<String>) -> Self {
68        Self::new("ServerDrainingError", msg)
69    }
70}
71
72impl fmt::Display for RpcError {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        write!(f, "{}: {}", self.error_type, self.message)
75    }
76}
77
78impl std::error::Error for RpcError {}
79
80/// Convenience alias for `Result<T, RpcError>`.
81pub type Result<T> = std::result::Result<T, RpcError>;
82
83impl From<arrow_schema::ArrowError> for RpcError {
84    fn from(e: arrow_schema::ArrowError) -> Self {
85        RpcError::new("ArrowError", e.to_string())
86    }
87}
88
89impl From<std::io::Error> for RpcError {
90    fn from(e: std::io::Error) -> Self {
91        RpcError::new("IOError", e.to_string())
92    }
93}