exchange_apiws/error.rs
1//! Error types — [`ExchangeError`] and the [`Result`] alias used throughout the crate.
2
3use thiserror::Error;
4
5/// All errors that can be returned by `exchange-apiws`.
6///
7/// Marked `#[non_exhaustive]` so downstream `match` arms must include a
8/// catch-all (`_`). This allows new variants to be added in minor releases
9/// without breaking callers.
10#[non_exhaustive]
11#[derive(Debug, Error)]
12pub enum ExchangeError {
13 /// HTTP transport error from `reqwest`.
14 #[error("HTTP error: {0}")]
15 Http(#[from] reqwest::Error),
16
17 /// WebSocket transport error from `tungstenite` (boxed to reduce enum size).
18 #[error("WebSocket error: {0}")]
19 WebSocket(Box<tokio_tungstenite::tungstenite::Error>),
20
21 /// JSON serialization or deserialization error.
22 #[error("JSON error: {0}")]
23 Json(#[from] serde_json::Error),
24
25 /// The exchange returned a non-success response code.
26 #[error("Exchange API error — code: {code}, msg: {message}")]
27 Api {
28 /// KuCoin error code string (e.g. `"400100"`).
29 code: String,
30 /// Human-readable error message from the exchange.
31 message: String,
32 },
33
34 /// HMAC signing or credential validation failed.
35 #[error("Authentication error: {0}")]
36 Auth(String),
37
38 /// A required configuration value is missing or invalid.
39 #[error("Config error: {0}")]
40 Config(String),
41
42 /// An order-level error (e.g. trying to close a flat position).
43 #[error("Order error: {0}")]
44 Order(String),
45
46 /// WebSocket feed gave up after exhausting all reconnect attempts.
47 ///
48 /// Carries the WS URL and the number of attempts made so callers can log
49 /// which feed died and how hard it tried.
50 #[error("WebSocket disconnected after {attempts} reconnect attempts on {url}")]
51 WsDisconnected {
52 /// The WSS URL that failed.
53 url: String,
54 /// Number of consecutive reconnect attempts before giving up.
55 attempts: u32,
56 },
57
58 /// Not enough historical data to complete the requested operation.
59 #[error("Insufficient data: {0}")]
60 InsufficientData(String),
61
62 /// Catch-all for errors from third-party libraries via `anyhow`.
63 #[error(transparent)]
64 Other(#[from] anyhow::Error),
65}
66
67impl From<tokio_tungstenite::tungstenite::Error> for ExchangeError {
68 fn from(e: tokio_tungstenite::tungstenite::Error) -> Self {
69 Self::WebSocket(Box::new(e))
70 }
71}
72
73/// Shorthand `Result` type used throughout the crate.
74pub type Result<T> = std::result::Result<T, ExchangeError>;