1//! Errors originating from API calls, parsing responses, and reading-or-writing to the file system.
2use serde::Deserialize;
34#[derive(Debug, thiserror::Error)]
5pub enum OpenAIError {
6/// Underlying error from reqwest library after an API call was made
7#[error("http error: {0}")]
8Reqwest(#[from] reqwest::Error),
9/// OpenAI returns error object with details of API call failure
10#[error("{0}")]
11ApiError(ApiError),
12/// Error when a response cannot be deserialized into a Rust type
13#[error("failed to deserialize api response: {0}")]
14JSONDeserialize(serde_json::Error),
15/// Error on the client side when saving file to file system
16#[error("failed to save file: {0}")]
17FileSaveError(String),
18/// Error on the client side when reading file from file system
19#[error("failed to read file: {0}")]
20FileReadError(String),
21/// Error on SSE streaming
22#[error("stream failed: {0}")]
23StreamError(String),
24/// Error from client side validation
25 /// or when builder fails to build request before making API call
26#[error("invalid args: {0}")]
27InvalidArgument(String),
28}
2930/// OpenAI API returns error object on failure
31#[derive(Debug, Deserialize, Clone)]
32pub struct ApiError {
33pub message: String,
34pub r#type: Option<String>,
35pub param: Option<String>,
36pub code: Option<String>,
37}
3839impl std::fmt::Display for ApiError {
40/// If all fields are available, `ApiError` is formatted as:
41 /// `{type}: {message} (param: {param}) (code: {code})`
42 /// Otherwise, missing fields will be ignored.
43fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44let mut parts = Vec::new();
4546if let Some(r#type) = &self.r#type {
47 parts.push(format!("{}:", r#type));
48 }
4950 parts.push(self.message.clone());
5152if let Some(param) = &self.param {
53 parts.push(format!("(param: {param})"));
54 }
5556if let Some(code) = &self.code {
57 parts.push(format!("(code: {code})"));
58 }
5960write!(f, "{}", parts.join(" "))
61 }
62}
6364/// Wrapper to deserialize the error object nested in "error" JSON key
65#[derive(Debug, Deserialize)]
66pub(crate) struct WrappedError {
67pub(crate) error: ApiError,
68}
6970pub(crate) fn map_deserialization_error(e: serde_json::Error, bytes: &[u8]) -> OpenAIError {
71tracing::error!(
72"failed deserialization of: {}",
73 String::from_utf8_lossy(bytes)
74 );
75 OpenAIError::JSONDeserialize(e)
76}