caravan_rpc/errors.rs
1//! Caravan RPC error types.
2//!
3//! Mirrors the Python SDK's `RpcRemoteError` / `RpcTransportError` split.
4//! Wire-version 1 keeps the error envelope simple: `{ok: false, error: {code,
5//! message}}` for logical failures; transport-level failures (timeout, 5xx,
6//! malformed body) become `RpcTransportError`.
7
8use thiserror::Error;
9
10/// Logical failure returned by a peer in the `{ok: false, error: {...}}`
11/// envelope. The `code` is the originating exception class name (Python) or
12/// the Rust error's `Debug` discriminant; `message` is the user-visible
13/// message.
14#[derive(Debug, Error)]
15#[error("remote error [{code}]: {message}")]
16pub struct RpcRemoteError {
17 pub code: String,
18 pub message: String,
19}
20
21/// Transport-level failure: connection refused, timeout, 5xx without an
22/// envelope body, malformed JSON, missing fields. Anything that prevents
23/// extracting a logical-failure envelope from the peer.
24#[derive(Debug, Error)]
25pub enum RpcTransportError {
26 #[error("http request failed: {0}")]
27 Http(String),
28 #[error("response body was not valid JSON: {0}")]
29 DecodeJson(String),
30 #[error("response envelope missing required field: {0}")]
31 DecodeEnvelope(&'static str),
32 #[error("response wire version {got:?} != expected {expected:?}")]
33 BadWireVersion { got: String, expected: &'static str },
34 #[error("peer returned HTTP {status} without a JSON envelope (body: {body:?})")]
35 BadStatus { status: u16, body: String },
36}
37
38/// Top-level error returned from dispatcher helpers. Either the peer rejected
39/// the call logically, or the transport layer failed.
40#[derive(Debug, Error)]
41pub enum RpcError {
42 #[error(transparent)]
43 Remote(#[from] RpcRemoteError),
44 #[error(transparent)]
45 Transport(#[from] RpcTransportError),
46}