Skip to main content

limitless/
errors.rs

1//! Error types for the Limitless Exchange API client.
2//!
3//! `LimitlessContentError` captures error details returned by the API itself.
4//! `LimitlessError` is the top-level error enum covering API errors, network
5//! failures, serialization issues, and validation errors.
6
7use crate::prelude::*;
8
9/// Represents an error returned by the Limitless API in the response body.
10///
11/// The `message` field contains the human-readable error description.
12/// The `code` field (if present) contains a machine-readable error code.
13#[derive(Debug, Deserialize, Display)]
14#[display("{}", message)]
15pub struct LimitlessContentError {
16    /// Human-readable error message from the API.
17    pub message: String,
18    /// Optional machine-readable error code.
19    #[serde(default)]
20    pub code: Option<String>,
21}
22
23/// Top-level error type covering all possible failures when interacting
24/// with the Limitless Exchange API.
25#[derive(Debug, Error)]
26pub enum LimitlessError {
27    /// The Limitless API returned an error response (4xx/5xx with a body).
28    #[error("Limitless API error: {0}")]
29    ApiError(LimitlessContentError),
30
31    /// Failed to send a value on an internal channel (WebSocket event loop).
32    #[error("Failed to emit value on channel: {underlying}")]
33    ChannelSendError { underlying: String },
34
35    /// Request parameters failed client-side validation before being sent.
36    #[error("Validation error: {0}")]
37    ValidationError(String),
38
39    /// Reqwest HTTP client error (network, DNS, TLS, timeout).
40    #[error(transparent)]
41    ReqError(#[from] reqwest::Error),
42
43    /// Invalid HTTP header value provided.
44    #[error(transparent)]
45    InvalidHeaderError(#[from] reqwest::header::InvalidHeaderValue),
46
47    /// Standard I/O error.
48    #[error(transparent)]
49    IoError(#[from] std::io::Error),
50
51    /// Failed to parse a string as a floating-point number.
52    #[error(transparent)]
53    ParseFloatError(#[from] std::num::ParseFloatError),
54
55    /// URL parsing failure.
56    #[error(transparent)]
57    UrlParserError(#[from] url::ParseError),
58
59    /// JSON serialization/deserialization error.
60    #[error(transparent)]
61    Json(#[from] serde_json::Error),
62
63    /// WebSocket protocol / transport error.
64    #[error(transparent)]
65    Tungstenite(#[from] tokio_tungstenite::tungstenite::Error),
66
67    /// System time error (clock may be before Unix epoch).
68    #[error(transparent)]
69    TimestampError(#[from] std::time::SystemTimeError),
70
71    /// Generic serde deserialization error.
72    #[error(transparent)]
73    SerdeError(#[from] serde::de::value::Error),
74
75    /// The server returned 500 Internal Server Error.
76    #[error("Internal Server Error")]
77    InternalServerError,
78
79    /// The server returned 503 Service Unavailable.
80    #[error("Service Unavailable")]
81    ServiceUnavailable,
82
83    /// The server returned 401 Unauthorized — check your API key/token.
84    #[error("Unauthorized — check API key or token")]
85    Unauthorized,
86
87    /// Rate-limited (429 Too Many Requests). Retry with backoff.
88    #[error("Rate limited — retry with exponential backoff")]
89    RateLimited,
90
91    /// The server returned an unexpected status code.
92    #[error("Unexpected status code: {0}")]
93    StatusCode(u16),
94
95    /// A catch-all for errors that do not fit other variants.
96    #[error("Limitless error: {0}")]
97    Base(String),
98}
99
100impl From<String> for LimitlessError {
101    fn from(err: String) -> Self {
102        LimitlessError::Base(err)
103    }
104}