litellm_rs/core/providers/replicate/
error.rs1use crate::core::providers::shared::parse_retry_after_from_body;
6use crate::core::providers::unified_provider::ProviderError;
7use crate::core::traits::error_mapper::trait_def::ErrorMapper;
8
9crate::impl_provider_error_helpers!("replicate", replicate);
11
12impl ProviderError {
14 pub fn replicate_prediction_failed(message: impl Into<String>) -> Self {
16 Self::api_error("replicate", 422, message.into())
17 }
18
19 pub fn replicate_prediction_timeout(message: impl Into<String>) -> Self {
21 Self::timeout("replicate", message)
22 }
23
24 pub fn replicate_prediction_canceled(message: impl Into<String>) -> Self {
26 Self::cancelled("replicate", "prediction", Some(message.into()))
27 }
28}
29
30#[derive(Debug)]
32pub struct ReplicateErrorMapper;
33
34impl ErrorMapper<ProviderError> for ReplicateErrorMapper {
35 fn map_http_error(&self, status_code: u16, response_body: &str) -> ProviderError {
36 match status_code {
37 401 => ProviderError::replicate_authentication("Invalid API token"),
38 403 => ProviderError::api_error("replicate", status_code, "Permission denied"),
40 404 => {
41 if response_body.contains("model") || response_body.contains("version") {
43 ProviderError::replicate_model_not_found(response_body)
44 } else {
45 ProviderError::replicate_api_error(404, response_body)
46 }
47 }
48 422 => {
49 ProviderError::replicate_prediction_failed(response_body)
51 }
52 429 => {
53 let retry_after = parse_retry_after_from_body(response_body);
55 ProviderError::replicate_rate_limit(retry_after)
56 }
57 500..=599 => ProviderError::provider_unavailable("replicate", response_body),
58 _ => ProviderError::replicate_api_error(status_code, response_body),
59 }
60 }
61
62 fn map_json_error(&self, error_response: &serde_json::Value) -> ProviderError {
63 let error_msg = error_response
67 .get("detail")
68 .and_then(|d| d.as_str())
69 .or_else(|| {
70 error_response
71 .get("error")
72 .and_then(|e| e.get("message"))
73 .and_then(|m| m.as_str())
74 })
75 .unwrap_or("Unknown error");
76
77 let error_type = error_response
78 .get("type")
79 .or_else(|| error_response.get("error").and_then(|e| e.get("type")))
80 .and_then(|t| t.as_str())
81 .unwrap_or("unknown");
82
83 match error_type {
84 "authentication_error" | "invalid_token" => {
85 ProviderError::replicate_authentication(error_msg)
86 }
87 "rate_limit_exceeded" => ProviderError::replicate_rate_limit(None),
88 "model_not_found" | "version_not_found" => {
89 ProviderError::replicate_model_not_found(error_msg)
90 }
91 "prediction_failed" => ProviderError::replicate_prediction_failed(error_msg),
92 _ => ProviderError::other("replicate", error_msg),
93 }
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_replicate_authentication_error() {
103 let err = ProviderError::replicate_authentication("Invalid API token");
104 assert!(err.is_replicate_error());
105 assert!(matches!(err, ProviderError::Authentication { .. }));
106 }
107
108 #[test]
109 fn test_replicate_rate_limit_error() {
110 let err = ProviderError::replicate_rate_limit(Some(60));
111 assert!(err.is_replicate_error());
112 assert!(matches!(err, ProviderError::RateLimit { .. }));
113 }
114
115 #[test]
116 fn test_replicate_model_not_found_error() {
117 let err = ProviderError::replicate_model_not_found("unknown/model");
118 assert!(err.is_replicate_error());
119 assert!(matches!(err, ProviderError::ModelNotFound { .. }));
120 }
121
122 #[test]
123 fn test_replicate_prediction_failed_error() {
124 let err = ProviderError::replicate_prediction_failed("Prediction failed");
125 assert!(err.is_replicate_error());
126 assert!(matches!(err, ProviderError::ApiError { status: 422, .. }));
127 }
128
129 #[test]
130 fn test_replicate_prediction_timeout_error() {
131 let err = ProviderError::replicate_prediction_timeout("Timeout waiting for result");
132 assert!(err.is_replicate_error());
133 assert!(matches!(err, ProviderError::Timeout { .. }));
134 }
135
136 #[test]
137 fn test_error_mapper_401() {
138 let mapper = ReplicateErrorMapper;
139 let err = mapper.map_http_error(401, "Unauthorized");
140 assert!(matches!(err, ProviderError::Authentication { .. }));
141 }
142
143 #[test]
144 fn test_error_mapper_403() {
145 let mapper = ReplicateErrorMapper;
146 let err = mapper.map_http_error(403, "Forbidden");
148 assert!(matches!(err, ProviderError::ApiError { status: 403, .. }));
149 }
150
151 #[test]
152 fn test_error_mapper_404_model() {
153 let mapper = ReplicateErrorMapper;
154 let err = mapper.map_http_error(404, "model not found");
155 assert!(matches!(err, ProviderError::ModelNotFound { .. }));
156 }
157
158 #[test]
159 fn test_error_mapper_404_other() {
160 let mapper = ReplicateErrorMapper;
161 let err = mapper.map_http_error(404, "resource not found");
162 assert!(matches!(err, ProviderError::ApiError { status: 404, .. }));
163 }
164
165 #[test]
166 fn test_error_mapper_422() {
167 let mapper = ReplicateErrorMapper;
168 let err = mapper.map_http_error(422, "Prediction failed");
169 assert!(matches!(err, ProviderError::ApiError { status: 422, .. }));
170 }
171
172 #[test]
173 fn test_error_mapper_429() {
174 let mapper = ReplicateErrorMapper;
175 let err = mapper.map_http_error(429, "rate limit exceeded");
176 assert!(matches!(err, ProviderError::RateLimit { .. }));
177 }
178
179 #[test]
180 fn test_error_mapper_500() {
181 let mapper = ReplicateErrorMapper;
182 let err = mapper.map_http_error(500, "Internal server error");
183 assert!(matches!(err, ProviderError::ProviderUnavailable { .. }));
184 }
185
186 #[test]
187 fn test_parse_retry_after_with_rate_limit() {
188 let result = parse_retry_after_from_body("rate limit exceeded");
189 assert_eq!(result, Some(60));
190 }
191
192 #[test]
193 fn test_parse_retry_after_with_too_many_requests() {
194 let result = parse_retry_after_from_body("too many requests");
195 assert_eq!(result, Some(60));
196 }
197
198 #[test]
199 fn test_parse_retry_after_no_match() {
200 let result = parse_retry_after_from_body("some other error");
201 assert_eq!(result, None);
202 }
203
204 #[test]
205 fn test_error_mapper_json_authentication() {
206 let mapper = ReplicateErrorMapper;
207 let json = serde_json::json!({
208 "type": "authentication_error",
209 "detail": "Invalid token"
210 });
211 let err = mapper.map_json_error(&json);
212 assert!(matches!(err, ProviderError::Authentication { .. }));
213 }
214
215 #[test]
216 fn test_error_mapper_json_model_not_found() {
217 let mapper = ReplicateErrorMapper;
218 let json = serde_json::json!({
219 "type": "model_not_found",
220 "detail": "Model not found"
221 });
222 let err = mapper.map_json_error(&json);
223 assert!(matches!(err, ProviderError::ModelNotFound { .. }));
224 }
225
226 #[test]
227 fn test_error_mapper_json_rate_limit() {
228 let mapper = ReplicateErrorMapper;
229 let json = serde_json::json!({
230 "type": "rate_limit_exceeded",
231 "detail": "Too many requests"
232 });
233 let err = mapper.map_json_error(&json);
234 assert!(matches!(err, ProviderError::RateLimit { .. }));
235 }
236
237 #[test]
238 fn test_error_mapper_json_unknown() {
239 let mapper = ReplicateErrorMapper;
240 let json = serde_json::json!({
241 "type": "unknown_error",
242 "detail": "Something went wrong"
243 });
244 let err = mapper.map_json_error(&json);
245 assert!(matches!(err, ProviderError::Other { .. }));
246 }
247
248 #[test]
249 fn test_replicate_prediction_canceled() {
250 let err = ProviderError::replicate_prediction_canceled("User cancelled");
251 assert!(err.is_replicate_error());
252 assert!(matches!(err, ProviderError::Cancelled { .. }));
253 }
254
255 #[test]
256 fn test_replicate_configuration_error() {
257 let err = ProviderError::replicate_configuration("Missing API token");
258 assert!(err.is_replicate_error());
259 assert!(matches!(err, ProviderError::Configuration { .. }));
260 }
261}