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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
use reqwest::{Error as ReqwestError, StatusCode};
use serde_json::Error as SerdeJsonError;
use solana_client::client_error::ClientError;
use solana_sdk::{
message::CompileError, sanitize::SanitizeError, signature::SignerError, transaction::TransactionError,
};
use thiserror::Error;
/// Represents all possible errors returned by the `Helius` client
///
/// This enum provides a detailed categorization of various error scenarios, ranging from network failures to data serialization issues
#[derive(Debug, Error)]
pub enum HeliusError {
/// Indicates an improperly formatted request
///
/// This error occurs when the request parameters do not meet the expected format, are missing required fields,
/// or contain invalid data
#[error("Bad request to {path}: {text}")]
BadRequest { path: String, text: String },
/// Represents errors from the Solana client
///
/// This captures errors from the Solana client library
#[error("Solana client error: {0}")]
ClientError(#[from] ClientError),
/// Indicates that a client has not been initialized
///
/// Returned when accessing `async_connection()` without enabling async via `HeliusBuilder` or `new_async()`
#[error("Client not initialized: {text}")]
ClientNotInitialized { text: String },
/// Represents compile errors from the Solana SDK
///
/// This captures all compile errors thrown by the Solana SDK
#[error("Compile error: {0}")]
CompileError(#[from] CompileError),
/// Represents errors that occur internally with Helius and our servers
///
/// If the server encounters an unexpected condition that prevents it from fulfilling the request, this error is returned.
/// It includes the HTTP status code and a more detailed message about what went wrong.
/// If you are seeing this error continually, please reach out to Helius support.
#[error("Internal server error: {code} - {text}")]
InternalError { code: StatusCode, text: String },
/// Indicates that a required input was either missing or invalid.
///
/// This error is used for scenarios where user input does not conform to expected values, such as an empty string for an API key
#[error("Invalid input: {0}")]
InvalidInput(String),
/// Covers general network failures
///
/// This could range from DNS resolution failures, lost connections, issues with Solana, or any issue that prevents the client from reaching the server
#[error("Network error: {0}")]
Network(ReqwestError),
/// Indicates the requested resource was not found
///
/// This error can occur if a specified identifier does not match any existing entities known to the server
#[error("Not found: {text}")]
NotFound { text: String },
/// Indicates too many requests are sent in a given amount of time
///
/// This error includes the path to help identify a throttled request. Please visit https://www.helius.dev/docs/billing/rate-limits to see all the
/// current rate limits for each standard plan
#[error("Too many requests made to {path}")]
RateLimitExceeded { path: String },
/// Indicates an error from the underlying HTTP client (i.e., reqwest)
///
/// This captures errors from the `reqwest` library specifically
#[error("Request error: {0}")]
ReqwestError(ReqwestError),
/// Occurs during the serialization or deserialization of JSON data
///
/// If the JSON data cannot be encoded or decoded, this error will be thrown, typically indicating an issue with the data structure
///
#[error("Serialization / Deserialization error: {0}")]
SerdeJson(SerdeJsonError),
/// Represents errors from the Solana SDK for signing operations
///
/// This captures errors from the signing operations in the Solana SDK
#[error("Signer error: {0}")]
SignerError(#[from] SignerError),
/// Indicates that the transaction confirmation timed out
///
/// For polling a transaction's confirmation status
#[error("Transaction confirmation timed out with error code {code}: {text}")]
Timeout { code: StatusCode, text: String },
/// Represents transaction errors from the Solana SDK
///
/// This captures errors that occur when processing transactions
#[error("Transaction error: {0}")]
TransactionError(#[from] TransactionError),
/// Indicates the request lacked valid authentication credentials
///
/// This error is returned in response to a missing, invalid, or expired API key
#[error("Unauthorized access to {path}: {text}")]
Unauthorized { path: String, text: String },
/// A fallback error used when an unexpected or uncategorized issue occurs
///
/// This error includes the HTTP status code and message to help with debugging, acting as a generic catch-all for all other errors
#[error("Unknown error has occurred: HTTP {code} - {text}")]
Unknown { code: StatusCode, text: String },
/// Indicates a failure in the underlying WebSocket (tungstenite) connection
///
/// This captures connection errors, protocol violations, and other WebSocket-level failures
#[error("Unable to connect to server: {0}")]
Tungstenite(#[from] tokio_tungstenite::tungstenite::Error),
/// Indicates the WebSocket connection was closed unexpectedly
///
/// Includes a message describing the close reason or frame
#[error("Websocket connection closed ({0})")]
WebsocketClosed(String),
/// Represents errors specific to the Helius enhanced (Geyser) WebSocket
///
/// Returned for subscription failures, unsupported cluster configurations, or server-side errors
#[error("Enhanced websocket: {message}: {reason}")]
EnhancedWebsocket { reason: String, message: String },
/// Indicates a failure to parse a URL
///
/// Returned when a provided RPC or WebSocket URL is malformed
#[error("Url parse error")]
UrlParseError(#[from] url::ParseError),
/// Indicates a TLS/SSL handshake or configuration error
///
/// Returned when the HTTP client fails to establish a secure connection
#[error("TLS error: {0}")]
TlsError(String),
}
impl HeliusError {
/// Converts a `StatusCode` and message into the appropriate `HeliusError`
///
/// This utility function helps map HTTP status codes to the more specific errors detailed in this enum
pub fn from_response_status(status: StatusCode, path: String, text: String) -> Self {
match status {
StatusCode::BAD_REQUEST => HeliusError::BadRequest { path, text },
StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN => HeliusError::Unauthorized { path, text },
StatusCode::NOT_FOUND => HeliusError::NotFound { text },
StatusCode::INTERNAL_SERVER_ERROR => HeliusError::InternalError { code: status, text },
StatusCode::TOO_MANY_REQUESTS => HeliusError::RateLimitExceeded { path },
_ => HeliusError::Unknown { code: status, text },
}
}
}
impl From<SerdeJsonError> for HeliusError {
/// Converts a `SerdeJsonError` into a `HeliusError`
///
/// This allows for the seamless integration of JSON parsing errors into the broader error handling system
fn from(err: SerdeJsonError) -> HeliusError {
HeliusError::SerdeJson(err)
}
}
impl From<SanitizeError> for HeliusError {
/// Converts a Solana `SanitizeError` into [`HeliusError::InvalidInput`]
fn from(err: SanitizeError) -> Self {
HeliusError::InvalidInput(err.to_string())
}
}
impl From<ReqwestError> for HeliusError {
/// Converts a `reqwest::Error` into the appropriate `HeliusError` variant
///
/// Builder errors (typically TLS configuration issues) are mapped to [`HeliusError::TlsError`],
/// while all other request errors are mapped to [`HeliusError::ReqwestError`]
fn from(err: reqwest::Error) -> Self {
if err.is_builder() {
HeliusError::TlsError(err.to_string())
} else {
HeliusError::ReqwestError(err)
}
}
}
/// A handy type alias for handling results across the Helius SDK
pub type Result<T> = std::result::Result<T, HeliusError>;