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