alloy_json_rpc/
error.rs

1use crate::{ErrorPayload, RpcRecv};
2use serde_json::value::RawValue;
3
4/// An RPC error.
5#[derive(Debug, thiserror::Error)]
6pub enum RpcError<E, ErrResp = Box<RawValue>> {
7    /// Server returned an error response.
8    #[error("server returned an error response: {0}")]
9    ErrorResp(ErrorPayload<ErrResp>),
10
11    /// Server returned a null response when a non-null response was expected.
12    #[error("server returned a null response when a non-null response was expected")]
13    NullResp,
14
15    /// Rpc server returned an unsupported feature.
16    #[error("unsupported feature: {0}")]
17    UnsupportedFeature(&'static str),
18
19    /// Returned when a local pre-processing step fails. This allows custom
20    /// errors from local signers or request pre-processors.
21    #[error("local usage error: {0}")]
22    LocalUsageError(#[source] Box<dyn std::error::Error + Send + Sync>),
23
24    /// JSON serialization error.
25    #[error("serialization error: {0}")]
26    SerError(
27        /// The underlying serde_json error.
28        // To avoid accidentally confusing ser and deser errors, we do not use
29        // the `#[from]` tag.
30        #[source]
31        serde_json::Error,
32    ),
33    /// JSON deserialization error.
34    #[error("deserialization error: {err}")]
35    DeserError {
36        /// The underlying serde_json error.
37        // To avoid accidentally confusing ser and deser errors, we do not use
38        // the `#[from]` tag.
39        #[source]
40        err: serde_json::Error,
41        /// For deser errors, the text that failed to deserialize.
42        text: String,
43    },
44
45    /// Transport error.
46    ///
47    /// This variant is used when the error occurs during communication.
48    #[error(transparent)]
49    Transport(
50        /// The underlying transport error.
51        #[from]
52        E,
53    ),
54}
55
56impl<E, ErrResp> RpcError<E, ErrResp>
57where
58    ErrResp: RpcRecv,
59{
60    /// Instantiate a new `ErrorResp` from an error response.
61    pub const fn err_resp(err: ErrorPayload<ErrResp>) -> Self {
62        Self::ErrorResp(err)
63    }
64
65    /// Instantiate a new `LocalUsageError` from a custom error.
66    pub fn local_usage(err: impl std::error::Error + Send + Sync + 'static) -> Self {
67        Self::LocalUsageError(err.into())
68    }
69
70    /// Instantiate a new `LocalUsageError` from a custom error message.
71    pub fn local_usage_str(err: &str) -> Self {
72        Self::LocalUsageError(err.into())
73    }
74
75    /// Instantiate a new `DeserError` from a [`serde_json::Error`] and the
76    /// text. This should be called when the error occurs during
77    /// deserialization.
78    ///
79    /// Note: This will check if the response is actually an [ErrorPayload], if so it will return a
80    /// [RpcError::ErrorResp].
81    pub fn deser_err(err: serde_json::Error, text: impl AsRef<str>) -> Self {
82        let text = text.as_ref();
83
84        // check if the response is actually an `ErrorPayload`
85        if let Ok(err) = serde_json::from_str::<ErrorPayload<ErrResp>>(text) {
86            return Self::ErrorResp(err);
87        }
88
89        Self::DeserError { err, text: text.to_owned() }
90    }
91}
92
93impl<E, ErrResp> RpcError<E, ErrResp> {
94    /// Instantiate a new `SerError` from a [`serde_json::Error`]. This
95    /// should be called when the error occurs during serialization.
96    pub const fn ser_err(err: serde_json::Error) -> Self {
97        Self::SerError(err)
98    }
99
100    /// Check if the error is a serialization error.
101    pub const fn is_ser_error(&self) -> bool {
102        matches!(self, Self::SerError(_))
103    }
104
105    /// Check if the error is a deserialization error.
106    pub const fn is_deser_error(&self) -> bool {
107        matches!(self, Self::DeserError { .. })
108    }
109
110    /// Check if the error is a transport error.
111    pub const fn is_transport_error(&self) -> bool {
112        matches!(self, Self::Transport(_))
113    }
114
115    /// Check if the error is an error response.
116    pub const fn is_error_resp(&self) -> bool {
117        matches!(self, Self::ErrorResp(_))
118    }
119
120    /// Check if the error is a null response.
121    pub const fn is_null_resp(&self) -> bool {
122        matches!(self, Self::NullResp)
123    }
124
125    /// Check if the error is an unsupported feature error.
126    pub const fn is_unsupported_feature(&self) -> bool {
127        matches!(self, Self::UnsupportedFeature(_))
128    }
129
130    /// Check if the error is a local usage error.
131    pub const fn is_local_usage_error(&self) -> bool {
132        matches!(self, Self::LocalUsageError(_))
133    }
134
135    /// Fallible conversion to an error response.
136    pub const fn as_error_resp(&self) -> Option<&ErrorPayload<ErrResp>> {
137        match self {
138            Self::ErrorResp(err) => Some(err),
139            _ => None,
140        }
141    }
142}