litellm_rs/utils/error/gateway_error/
response.rs1use super::types::GatewayError;
4use crate::core::providers::unified_provider::ProviderError;
5use crate::utils::error::canonical::CanonicalError;
6use actix_web::{HttpResponse, ResponseError};
7
8impl ResponseError for GatewayError {
9 fn error_response(&self) -> HttpResponse {
10 let (status_code, error_code, message) = match self {
11 GatewayError::Config(_) => (
12 actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
13 "CONFIG_ERROR",
14 self.to_string(),
15 ),
16 GatewayError::Storage(_) => (
17 actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
18 "STORAGE_ERROR",
19 self.to_string(),
20 ),
21 GatewayError::Auth(_) => (
22 actix_web::http::StatusCode::UNAUTHORIZED,
23 "AUTH_ERROR",
24 self.to_string(),
25 ),
26 GatewayError::Forbidden(_) => (
27 actix_web::http::StatusCode::FORBIDDEN,
28 "FORBIDDEN",
29 self.to_string(),
30 ),
31 GatewayError::Provider(provider_error) => match provider_error {
32 ProviderError::RateLimit { .. } => (
33 actix_web::http::StatusCode::TOO_MANY_REQUESTS,
34 "PROVIDER_RATE_LIMIT",
35 provider_error.to_string(),
36 ),
37 ProviderError::QuotaExceeded { .. } => (
38 actix_web::http::StatusCode::PAYMENT_REQUIRED,
39 "PROVIDER_QUOTA_EXCEEDED",
40 provider_error.to_string(),
41 ),
42 ProviderError::ModelNotFound { .. } => (
43 actix_web::http::StatusCode::NOT_FOUND,
44 "MODEL_NOT_FOUND",
45 provider_error.to_string(),
46 ),
47 ProviderError::InvalidRequest { .. } => (
48 actix_web::http::StatusCode::BAD_REQUEST,
49 "INVALID_REQUEST",
50 provider_error.to_string(),
51 ),
52 ProviderError::Timeout { .. } => (
53 actix_web::http::StatusCode::GATEWAY_TIMEOUT,
54 "PROVIDER_TIMEOUT",
55 provider_error.to_string(),
56 ),
57 ProviderError::ProviderUnavailable { .. } => (
58 actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
59 "PROVIDER_UNAVAILABLE",
60 provider_error.to_string(),
61 ),
62 ProviderError::Authentication { .. } => (
63 actix_web::http::StatusCode::UNAUTHORIZED,
64 "PROVIDER_AUTH_ERROR",
65 provider_error.to_string(),
66 ),
67 ProviderError::Network { .. } => (
68 actix_web::http::StatusCode::BAD_GATEWAY,
69 "PROVIDER_NETWORK_ERROR",
70 provider_error.to_string(),
71 ),
72 ProviderError::Configuration { .. }
73 | ProviderError::Serialization { .. }
74 | ProviderError::TransformationError { .. } => (
75 actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
76 "PROVIDER_INTERNAL_ERROR",
77 provider_error.to_string(),
78 ),
79 ProviderError::ContextLengthExceeded { .. }
80 | ProviderError::ContentFiltered { .. }
81 | ProviderError::TokenLimitExceeded { .. } => (
82 actix_web::http::StatusCode::BAD_REQUEST,
83 "PROVIDER_REQUEST_ERROR",
84 provider_error.to_string(),
85 ),
86 ProviderError::NotSupported { .. }
87 | ProviderError::NotImplemented { .. }
88 | ProviderError::FeatureDisabled { .. } => (
89 actix_web::http::StatusCode::NOT_IMPLEMENTED,
90 "PROVIDER_NOT_IMPLEMENTED",
91 provider_error.to_string(),
92 ),
93 ProviderError::DeploymentError { .. } => (
94 actix_web::http::StatusCode::NOT_FOUND,
95 "DEPLOYMENT_NOT_FOUND",
96 provider_error.to_string(),
97 ),
98 ProviderError::ResponseParsing { .. } | ProviderError::Streaming { .. } => (
99 actix_web::http::StatusCode::BAD_GATEWAY,
100 "PROVIDER_RESPONSE_ERROR",
101 provider_error.to_string(),
102 ),
103 ProviderError::RoutingError { .. } => (
104 actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
105 "PROVIDER_ROUTING_ERROR",
106 provider_error.to_string(),
107 ),
108 ProviderError::ApiError { status, .. } => (
109 actix_web::http::StatusCode::from_u16(*status)
110 .unwrap_or(actix_web::http::StatusCode::BAD_GATEWAY),
111 "PROVIDER_API_ERROR",
112 provider_error.to_string(),
113 ),
114 ProviderError::Cancelled { .. } => (
115 actix_web::http::StatusCode::from_u16(499)
116 .unwrap_or(actix_web::http::StatusCode::BAD_REQUEST),
117 "PROVIDER_CANCELLED",
118 provider_error.to_string(),
119 ),
120 ProviderError::Other { .. } => (
121 actix_web::http::StatusCode::BAD_GATEWAY,
122 "PROVIDER_ERROR",
123 provider_error.to_string(),
124 ),
125 },
126 GatewayError::RateLimit { .. } => (
127 actix_web::http::StatusCode::TOO_MANY_REQUESTS,
128 "RATE_LIMIT_EXCEEDED",
129 self.to_string(),
130 ),
131 GatewayError::Validation(_) => (
132 actix_web::http::StatusCode::BAD_REQUEST,
133 "VALIDATION_ERROR",
134 self.to_string(),
135 ),
136 GatewayError::NotFound(_) => (
137 actix_web::http::StatusCode::NOT_FOUND,
138 "NOT_FOUND",
139 self.to_string(),
140 ),
141 GatewayError::Conflict(_) => (
142 actix_web::http::StatusCode::CONFLICT,
143 "CONFLICT",
144 self.to_string(),
145 ),
146 GatewayError::BadRequest(_) => (
147 actix_web::http::StatusCode::BAD_REQUEST,
148 "BAD_REQUEST",
149 self.to_string(),
150 ),
151 GatewayError::Timeout(_) => (
152 actix_web::http::StatusCode::REQUEST_TIMEOUT,
153 "TIMEOUT",
154 self.to_string(),
155 ),
156 GatewayError::Unavailable(_) => (
157 actix_web::http::StatusCode::SERVICE_UNAVAILABLE,
158 "SERVICE_UNAVAILABLE",
159 self.to_string(),
160 ),
161 GatewayError::Network(_) => (
162 actix_web::http::StatusCode::BAD_GATEWAY,
163 "NETWORK_ERROR",
164 self.to_string(),
165 ),
166 GatewayError::Internal(_) => (
167 actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
168 "INTERNAL_ERROR",
169 self.to_string(),
170 ),
171 GatewayError::NotImplemented(_) => (
172 actix_web::http::StatusCode::NOT_IMPLEMENTED,
173 "NOT_IMPLEMENTED",
174 self.to_string(),
175 ),
176 GatewayError::Serialization(_) => (
177 actix_web::http::StatusCode::BAD_REQUEST,
178 "SERIALIZATION_ERROR",
179 self.to_string(),
180 ),
181 GatewayError::HttpClient(_) => (
182 actix_web::http::StatusCode::BAD_GATEWAY,
183 "HTTP_CLIENT_ERROR",
184 self.to_string(),
185 ),
186 GatewayError::Io(_) => (
187 actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
188 "IO_ERROR",
189 self.to_string(),
190 ),
191 };
192
193 let canonical_code = self.canonical_code().as_str().to_string();
194 let retryable = self.canonical_retryable();
195
196 let error_response = GatewayErrorResponse {
197 error: GatewayErrorDetail {
198 code: error_code.to_string(),
199 canonical_code,
200 retryable,
201 message,
202 timestamp: chrono::Utc::now().timestamp(),
203 request_id: None, },
205 };
206
207 let mut builder = HttpResponse::build(status_code);
208
209 if let GatewayError::RateLimit {
211 retry_after,
212 rpm_limit,
213 tpm_limit,
214 ..
215 } = self
216 {
217 if let Some(secs) = retry_after {
218 builder.insert_header(("Retry-After", secs.to_string()));
219 }
220 if let Some(rpm) = rpm_limit {
221 builder.insert_header(("X-RateLimit-Limit-Requests", rpm.to_string()));
222 }
223 if let Some(tpm) = tpm_limit {
224 builder.insert_header(("X-RateLimit-Limit-Tokens", tpm.to_string()));
225 }
226 }
227
228 builder.json(error_response)
229 }
230}
231
232#[derive(serde::Serialize)]
234pub struct GatewayErrorResponse {
235 pub error: GatewayErrorDetail,
236}
237
238#[derive(serde::Serialize)]
240pub struct GatewayErrorDetail {
241 pub code: String,
242 pub canonical_code: String,
243 pub retryable: bool,
244 pub message: String,
245 pub timestamp: i64,
246 pub request_id: Option<String>,
247}
248
249#[cfg(test)]
250#[path = "response_tests.rs"]
251mod tests;
252
253#[cfg(test)]
254#[path = "response_consolidation_tests.rs"]
255mod consolidation_tests;