Skip to main content

rust_okx/
error.rs

1//! Error types returned by the crate.
2
3use crate::model::RequestValidationError;
4use crate::transport::TransportError;
5#[cfg(feature = "websocket")]
6pub use crate::ws::WsError;
7
8type BoxError = Box<dyn std::error::Error + Send + Sync>;
9
10/// A type alias for [`std::result::Result`] using this crate's [`Error`].
11pub type Result<T> = std::result::Result<T, Error>;
12
13/// Top-level error type.
14///
15/// Wraps [`RestError`] (REST layer), optionally [`WsError`] (WebSocket layer),
16/// and [`RequestValidationError`] (shared pre-flight validation).
17///
18/// The enum is [`#[non_exhaustive]`](https://doc.rust-lang.org/reference/attributes/type_system.html)
19/// so new variants can be added without a breaking change.
20#[derive(Debug, thiserror::Error)]
21#[non_exhaustive]
22pub enum Error {
23    /// An error from the REST API layer.
24    #[error(transparent)]
25    Rest(#[from] RestError),
26
27    /// An error from the WebSocket layer.
28    #[cfg(feature = "websocket")]
29    #[error(transparent)]
30    Ws(#[from] WsError),
31
32    /// The typed request failed client-side validation before it was sent.
33    #[error("invalid request: {0}")]
34    InvalidRequest(#[from] RequestValidationError),
35}
36
37/// Errors from the REST API layer.
38#[derive(Debug, thiserror::Error)]
39#[non_exhaustive]
40pub enum RestError {
41    /// The underlying HTTP transport failed (connection, TLS, timeout, …).
42    #[error("transport error: {source}")]
43    Transport {
44        /// Finding the position of the error
45        #[from]
46        source: TransportError,
47    },
48
49    /// The HTTP response had a non-success status before the OKX envelope
50    /// could be decoded.
51    #[error("HTTP {status} from {endpoint}")]
52    HttpStatus {
53        /// The endpoint path, e.g. `/api/v5/account/balance`.
54        endpoint: &'static str,
55        /// HTTP response status code.
56        status: http::StatusCode,
57        /// Response body, decoded lossily as UTF-8 for diagnostics.
58        body: String,
59    },
60
61    /// OKX returned a non-zero response code.
62    #[error("OKX API error {code} from {endpoint}: {message}")]
63    Okx {
64        /// The endpoint path.
65        endpoint: &'static str,
66        /// OKX error code (e.g. `"50011"`). Kept as a string deliberately.
67        code: String,
68        /// Human-readable error message from OKX.
69        message: String,
70    },
71
72    /// The response body could not be decoded into the expected model.
73    #[error("failed to decode response from {endpoint}")]
74    Decode {
75        /// The endpoint path.
76        endpoint: &'static str,
77        /// The underlying deserialization error.
78        #[source]
79        source: serde_json::Error,
80    },
81
82    /// The request could not be encoded (query string, JSON body, or headers).
83    #[error("failed to encode request")]
84    Encode {
85        /// The underlying encoding error.
86        #[source]
87        source: BoxError,
88    },
89
90    /// The client was used in an invalid way (e.g. an authenticated endpoint
91    /// was called without credentials).
92    #[error("invalid configuration: {0}")]
93    Configuration(String),
94}