replicate_client/
error.rs

1//! Error types for the Replicate client.
2
3use thiserror::Error;
4
5/// Result type alias for Replicate operations.
6pub type Result<T> = std::result::Result<T, Error>;
7
8/// Main error type for the Replicate client.
9#[derive(Error, Debug)]
10pub enum Error {
11    /// HTTP request failed
12    #[error("HTTP request failed: {0}")]
13    Http(#[from] reqwest::Error),
14
15    /// HTTP middleware error
16    #[error("HTTP middleware error: {0}")]
17    HttpMiddleware(#[from] reqwest_middleware::Error),
18
19    /// JSON serialization/deserialization error
20    #[error("JSON error: {0}")]
21    Json(#[from] serde_json::Error),
22
23    /// API returned an error response
24    #[error("API error: {status} - {message}")]
25    Api {
26        status: u16,
27        message: String,
28        detail: Option<String>,
29    },
30
31    /// Authentication error
32    #[error("Authentication error: {0}")]
33    Auth(String),
34
35    /// Invalid input or configuration
36    #[error("Invalid input: {0}")]
37    InvalidInput(String),
38
39    /// File operation error
40    #[error("File error: {0}")]
41    File(#[from] std::io::Error),
42
43    /// URL parsing error
44    #[error("URL error: {0}")]
45    Url(#[from] url::ParseError),
46
47    /// Model execution error
48    #[error("Model execution failed: {prediction_id}")]
49    ModelExecution {
50        prediction_id: String,
51        error_message: Option<String>,
52        logs: Option<String>,
53    },
54
55    /// Timeout error
56    #[error("Operation timed out: {0}")]
57    Timeout(String),
58
59    /// Unsupported operation
60    #[error("Unsupported operation: {0}")]
61    Unsupported(String),
62}
63
64impl Error {
65    /// Create a new API error
66    pub fn api_error(status: u16, message: impl Into<String>) -> Self {
67        Self::Api {
68            status,
69            message: message.into(),
70            detail: None,
71        }
72    }
73
74    /// Create a new API error with detail
75    pub fn api_error_with_detail(
76        status: u16,
77        message: impl Into<String>,
78        detail: impl Into<String>,
79    ) -> Self {
80        Self::Api {
81            status,
82            message: message.into(),
83            detail: Some(detail.into()),
84        }
85    }
86
87    /// Create an authentication error
88    pub fn auth_error(message: impl Into<String>) -> Self {
89        Self::Auth(message.into())
90    }
91
92    /// Create an invalid input error
93    pub fn invalid_input(message: impl Into<String>) -> Self {
94        Self::InvalidInput(message.into())
95    }
96
97    /// Create a model execution error
98    pub fn model_execution(
99        prediction_id: impl Into<String>,
100        error_message: Option<String>,
101        logs: Option<String>,
102    ) -> Self {
103        Self::ModelExecution {
104            prediction_id: prediction_id.into(),
105            error_message,
106            logs,
107        }
108    }
109
110    /// Create a timeout error
111    pub fn timeout(message: impl Into<String>) -> Self {
112        Self::Timeout(message.into())
113    }
114
115    /// Create an unsupported operation error
116    pub fn unsupported(message: impl Into<String>) -> Self {
117        Self::Unsupported(message.into())
118    }
119}
120
121/// Helper trait for converting HTTP status codes to errors
122pub trait StatusCodeExt {
123    fn to_replicate_error(self, body: String) -> Error;
124}
125
126impl StatusCodeExt for reqwest::StatusCode {
127    fn to_replicate_error(self, body: String) -> Error {
128        match self.as_u16() {
129            401 => Error::auth_error("Invalid API token"),
130            402 => Error::auth_error("Insufficient credits"),
131            403 => Error::auth_error("Forbidden"),
132            404 => Error::api_error(404, "Resource not found"),
133            422 => Error::api_error_with_detail(422, "Validation error", body),
134            429 => Error::api_error(429, "Rate limit exceeded"),
135            500..=599 => Error::api_error(self.as_u16(), "Server error"),
136            _ => Error::api_error(self.as_u16(), body),
137        }
138    }
139}