Skip to main content

chainrpc_core/
error.rs

1//! Transport-level error types.
2
3use thiserror::Error;
4
5use crate::request::JsonRpcError;
6
7/// Errors that can occur during an RPC transport operation.
8#[derive(Debug, Error)]
9pub enum TransportError {
10    /// HTTP request failed (connection refused, timeout, etc.).
11    #[error("HTTP error: {0}")]
12    Http(String),
13
14    /// WebSocket connection/send/receive error.
15    #[error("WebSocket error: {0}")]
16    WebSocket(String),
17
18    /// JSON-RPC protocol-level error returned by the node.
19    #[error("RPC error {}: {}", .0.code, .0.message)]
20    Rpc(JsonRpcError),
21
22    /// Rate limit exceeded — caller should back off.
23    #[error("Rate limit exceeded (provider: {provider})")]
24    RateLimited { provider: String },
25
26    /// Circuit breaker is open — provider is unhealthy.
27    #[error("Circuit breaker open for provider: {provider}")]
28    CircuitOpen { provider: String },
29
30    /// All providers in the pool are unavailable.
31    #[error("All providers unavailable")]
32    AllProvidersDown,
33
34    /// Request timed out after the configured duration.
35    #[error("Request timed out after {ms}ms")]
36    Timeout { ms: u64 },
37
38    /// Response could not be deserialized.
39    #[error("Deserialization error: {0}")]
40    Deserialization(#[from] serde_json::Error),
41
42    /// Request rejected due to backpressure — too many in-flight requests.
43    #[error("Transport overloaded ({queue_depth} requests in flight)")]
44    Overloaded { queue_depth: usize },
45
46    /// Operation was cancelled via cancellation token.
47    #[error("Operation cancelled")]
48    Cancelled,
49
50    /// An unexpected error.
51    #[error("{0}")]
52    Other(String),
53}
54
55impl TransportError {
56    /// Returns `true` if this error is retryable (transient).
57    pub fn is_retryable(&self) -> bool {
58        matches!(
59            self,
60            Self::Http(_) | Self::WebSocket(_) | Self::Timeout { .. } | Self::RateLimited { .. }
61        )
62    }
63
64    /// Returns `true` if this is a node-side execution error (not retryable).
65    pub fn is_execution_error(&self) -> bool {
66        matches!(self, Self::Rpc(_))
67    }
68}