1use reqwest::StatusCode;
2use serde::{Deserialize, Serialize};
3use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum AnthropicError {
8 #[error("HTTP error: {0}")]
10 Reqwest(#[from] reqwest::Error),
11
12 #[error("API error: {0:?}")]
14 Api(ApiErrorObject),
15
16 #[error("Invalid configuration: {0}")]
18 Config(String),
19
20 #[error("Serialization error: {0}")]
22 Serde(String),
23}
24
25#[derive(Debug, Clone, Serialize, Deserialize)]
27pub struct ApiErrorObject {
28 pub r#type: Option<String>,
30 pub message: String,
32 pub request_id: Option<String>,
34 pub code: Option<String>,
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
39struct ErrorEnvelope {
40 error: ApiErrorObject,
41}
42
43#[must_use]
47pub fn map_deser(e: &serde_json::Error, body: &[u8]) -> AnthropicError {
48 let snippet = String::from_utf8_lossy(&body[..body.len().min(400)]).to_string();
49 AnthropicError::Serde(format!("{e}: {snippet}"))
50}
51
52#[must_use]
56pub fn deserialize_api_error(status: StatusCode, body: &[u8]) -> AnthropicError {
57 if let Ok(envelope) = serde_json::from_slice::<ErrorEnvelope>(body) {
58 return AnthropicError::Api(envelope.error);
59 }
60
61 AnthropicError::Api(ApiErrorObject {
63 r#type: Some(format!("http_{}", status.as_u16())),
64 message: String::from_utf8_lossy(body).into_owned(),
65 request_id: None,
66 code: None,
67 })
68}