Skip to main content

agentik_sdk/types/
errors.rs

1use thiserror::Error;
2
3#[derive(Error, Debug, Clone)]
4pub enum AnthropicError {
5    #[error("Bad request: {message}")]
6    BadRequest { message: String, status: u16 },
7    
8    #[error("Authentication failed: {message}")]
9    Authentication { message: String, status: u16 },
10    
11    #[error("Permission denied: {message}")]
12    PermissionDenied { message: String, status: u16 },
13    
14    #[error("Resource not found: {message}")]
15    NotFound { message: String, status: u16 },
16    
17    #[error("Unprocessable entity: {message}")]
18    UnprocessableEntity { message: String, status: u16 },
19    
20    #[error("Rate limit exceeded: {message}")]
21    RateLimit { message: String, status: u16 },
22    
23    #[error("Internal server error: {message}")]
24    InternalServer { message: String, status: u16 },
25    
26    #[error("API connection error: {message}")]
27    Connection { message: String },
28    
29    #[error("API connection timeout")]
30    ConnectionTimeout,
31    
32    #[error("User aborted request")]
33    UserAbort,
34    
35    #[error("Streaming error: {0}")]
36    StreamError(String),
37    
38    #[error("Invalid configuration: {message}")]
39    Configuration { message: String },
40    
41    #[error("Invalid API key")]
42    InvalidApiKey,
43    
44    #[error("Request timeout")]
45    Timeout,
46    
47    #[error("Network error: {0}")]
48    NetworkError(String),
49    
50    #[error("HTTP error: {status} - {message}")]
51    HttpError { status: u16, message: String },
52    
53    #[error("Service unavailable: {message}")]
54    ServiceUnavailable { message: String },
55    
56    #[error("{0}")]
57    Other(String),
58}
59
60impl AnthropicError {
61    /// Create an error from HTTP response status and message
62    pub fn from_status(status: u16, message: String) -> Self {
63        match status {
64            400 => Self::BadRequest { message, status },
65            401 => Self::Authentication { message, status },
66            403 => Self::PermissionDenied { message, status },
67            404 => Self::NotFound { message, status },
68            422 => Self::UnprocessableEntity { message, status },
69            429 => Self::RateLimit { message, status },
70            500..=599 => Self::InternalServer { message, status },
71            _ => Self::InternalServer { message, status },
72        }
73    }
74    
75    /// Get the HTTP status code if available
76    pub fn status_code(&self) -> Option<u16> {
77        match self {
78            Self::BadRequest { status, .. } |
79            Self::Authentication { status, .. } |
80            Self::PermissionDenied { status, .. } |
81            Self::NotFound { status, .. } |
82            Self::UnprocessableEntity { status, .. } |
83            Self::RateLimit { status, .. } |
84            Self::InternalServer { status, .. } => Some(*status),
85            _ => None,
86        }
87    }
88}
89
90impl From<reqwest::Error> for AnthropicError {
91    fn from(err: reqwest::Error) -> Self {
92        if err.is_timeout() {
93            Self::Timeout
94        } else if err.is_connect() {
95            Self::Connection { 
96                message: err.to_string() 
97            }
98        } else if err.is_request() {
99            Self::HttpError { 
100                status: err.status().map(|s| s.as_u16()).unwrap_or(0), 
101                message: err.to_string() 
102            }
103        } else {
104            Self::NetworkError(err.to_string())
105        }
106    }
107}
108
109impl From<serde_json::Error> for AnthropicError {
110    fn from(err: serde_json::Error) -> Self {
111        Self::Other(format!("JSON serialization/deserialization error: {}", err))
112    }
113}
114
115impl From<chrono::OutOfRangeError> for AnthropicError {
116    fn from(err: chrono::OutOfRangeError) -> Self {
117        Self::Other(format!("Date/time out of range error: {}", err))
118    }
119}
120
121pub type Result<T> = std::result::Result<T, AnthropicError>;