Skip to main content

yfinance/
error.rs

1//! Error and result types.
2
3use std::fmt;
4
5/// Convenient `Result` alias used throughout the crate.
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// All errors produced by this crate.
9#[derive(Debug, thiserror::Error)]
10#[non_exhaustive]
11pub enum Error {
12    /// Underlying HTTP transport failure.
13    #[error("http error: {0}")]
14    Http(#[from] reqwest::Error),
15
16    /// JSON decoding failure.
17    #[error("json error: {0}")]
18    Json(#[from] serde_json::Error),
19
20    /// URL parsing failure.
21    #[error("url error: {0}")]
22    Url(#[from] url::ParseError),
23
24    /// Yahoo returned a non-success status code.
25    #[error("yahoo returned status {status}: {message}")]
26    Status {
27        /// HTTP status code.
28        status: u16,
29        /// Best-effort message extracted from the response body.
30        message: String,
31    },
32
33    /// Yahoo's chart/v8 endpoint returned an explicit error payload.
34    #[error("yahoo error [{code}] for {symbol}: {description}")]
35    Yahoo {
36        /// Symbol that triggered the error.
37        symbol: String,
38        /// Yahoo error code (e.g. `Not Found`).
39        code: String,
40        /// Human-readable description.
41        description: String,
42    },
43
44    /// We got a 429 from Yahoo and exhausted retry budget.
45    #[error("rate limited by Yahoo (HTTP 429)")]
46    RateLimited,
47
48    /// Could not obtain an authenticated session (cookie + crumb).
49    #[error("could not authenticate with Yahoo: {0}")]
50    Auth(String),
51
52    /// The ticker symbol is missing or delisted.
53    #[error("ticker `{ticker}` not found: {reason}")]
54    TickerMissing {
55        /// The requested symbol.
56        ticker: String,
57        /// Reason supplied by the upstream API or our parser.
58        reason: String,
59    },
60
61    /// The ticker has no timezone info — usually means delisted.
62    #[error("ticker `{0}` has no timezone metadata")]
63    TimezoneMissing(String),
64
65    /// No price data returned for the requested period/interval.
66    #[error("no prices returned for `{ticker}` ({hint})")]
67    PricesMissing {
68        /// The requested symbol.
69        ticker: String,
70        /// Human-readable hint about why data was missing.
71        hint: String,
72    },
73
74    /// The requested period/interval combination is not allowed.
75    #[error("invalid period/interval for `{ticker}`: {reason}")]
76    InvalidPeriod {
77        /// The requested symbol.
78        ticker: String,
79        /// Why the combination is invalid.
80        reason: String,
81    },
82
83    /// A response field had an unexpected shape.
84    #[error("unexpected response shape: {0}")]
85    UnexpectedResponse(String),
86
87    /// A required argument was invalid.
88    #[error("invalid argument: {0}")]
89    InvalidArgument(String),
90
91    /// Catch-all for unexpected I/O.
92    #[error(transparent)]
93    Io(#[from] std::io::Error),
94}
95
96impl Error {
97    /// Construct an [`Error::UnexpectedResponse`] with a formatted message.
98    pub fn unexpected(msg: impl fmt::Display) -> Self {
99        Error::UnexpectedResponse(msg.to_string())
100    }
101
102    /// Construct an [`Error::InvalidArgument`] with a formatted message.
103    pub fn invalid(msg: impl fmt::Display) -> Self {
104        Error::InvalidArgument(msg.to_string())
105    }
106}