Skip to main content

objectiveai_sdk/http/
error.rs

1//! HTTP error types.
2
3use crate::error;
4
5/// Errors that can occur during HTTP operations.
6#[derive(thiserror::Error, Debug)]
7pub enum HttpError {
8    /// Failed to deserialize the response body.
9    ///
10    /// Includes path information to help identify which field caused the error.
11    #[error("deserialization error: {0}")]
12    DeserializationError(#[from] serde_path_to_error::Error<serde_json::Error>),
13
14    /// The server returned a non-success HTTP status code.
15    #[error("received bad status code: {code}, body: {body}")]
16    BadStatus {
17        /// The HTTP status code (e.g., 400, 401, 500).
18        code: reqwest::StatusCode,
19        /// Response body, parsed as JSON if possible, otherwise as a string.
20        body: serde_json::Value,
21    },
22
23    /// Error occurred while reading from an SSE stream.
24    #[error("error fetching stream: {0}")]
25    StreamError(#[from] reqwest_eventsource::Error),
26
27    /// Failed to build the HTTP request.
28    #[error("request error: {0}")]
29    RequestError(reqwest::Error),
30
31    /// Failed to establish a streaming connection.
32    ///
33    /// Occurs when the request cannot be cloned for SSE retry logic.
34    #[error("streaming request error: {0}")]
35    StreamingRequestError(#[from] reqwest_eventsource::CannotCloneRequestError),
36
37    /// General HTTP transport error (network, timeout, etc.).
38    #[error("http error: {0}")]
39    HttpError(reqwest::Error),
40
41    /// The API returned a structured error response.
42    #[error(transparent)]
43    ApiError(#[from] error::ResponseError),
44}
45
46impl error::StatusError for HttpError {
47    fn status(&self) -> u16 {
48        match self {
49            HttpError::DeserializationError(_) => 500,
50            HttpError::BadStatus { code, .. } => code.as_u16(),
51            HttpError::StreamError(reqwest_eventsource::Error::Transport(
52                e,
53            )) => e.status().map(|s| s.as_u16()).unwrap_or(500),
54            HttpError::StreamError(
55                reqwest_eventsource::Error::InvalidStatusCode(code, _),
56            ) => code.as_u16(),
57            HttpError::StreamError(_) => 500,
58            HttpError::RequestError(e) => {
59                e.status().map(|s| s.as_u16()).unwrap_or(500)
60            }
61            HttpError::StreamingRequestError(_) => 500,
62            HttpError::HttpError(e) => {
63                e.status().map(|s| s.as_u16()).unwrap_or(500)
64            }
65            HttpError::ApiError(e) => e.status(),
66        }
67    }
68
69    fn message(&self) -> Option<serde_json::Value> {
70        Some(serde_json::json!({
71            "kind": "objectiveai_client",
72            "error": match self {
73                HttpError::DeserializationError(e) => serde_json::json!({
74                    "kind": "deserialization",
75                    "error": e.to_string(),
76                }),
77                HttpError::BadStatus { body, .. } => serde_json::json!({
78                    "kind": "bad_status",
79                    "error": body,
80                }),
81                HttpError::StreamError(e) => serde_json::json!({
82                    "kind": "stream_error",
83                    "error": e.to_string(),
84                }),
85                HttpError::RequestError(e) => serde_json::json!({
86                    "kind": "request_error",
87                    "error": e.to_string(),
88                }),
89                HttpError::StreamingRequestError(e) => serde_json::json!({
90                    "kind": "streaming_request_error",
91                    "error": e.to_string(),
92                }),
93                HttpError::HttpError(e) => serde_json::json!({
94                    "kind": "http_error",
95                    "error": e.to_string(),
96                }),
97                HttpError::ApiError(e) => serde_json::json!({
98                    "kind": "api_error",
99                    "error": e.message(),
100                }),
101            }
102        }))
103    }
104}