1use std::any::Any;
16use std::net::SocketAddr;
17use std::string::FromUtf8Error;
18
19use axum::http::StatusCode as HttpStatusCode;
20use axum::response::{IntoResponse, Response};
21use axum::{http, Json};
22use base64::DecodeError;
23use common_error::define_into_tonic_status;
24use common_error::ext::{BoxedError, ErrorExt};
25use common_error::status_code::StatusCode;
26use common_macro::stack_trace_debug;
27use common_telemetry::{error, warn};
28use common_time::Duration;
29use datafusion::error::DataFusionError;
30use datatypes::prelude::ConcreteDataType;
31use headers::ContentType;
32use http::header::InvalidHeaderValue;
33use query::parser::PromQuery;
34use serde_json::json;
35use snafu::{Location, Snafu};
36
37#[derive(Snafu)]
38#[snafu(visibility(pub))]
39#[stack_trace_debug]
40pub enum Error {
41 #[snafu(display("Failed to bind address: {}", addr))]
42 AddressBind {
43 addr: SocketAddr,
44 #[snafu(source)]
45 error: std::io::Error,
46 #[snafu(implicit)]
47 location: Location,
48 },
49
50 #[snafu(display("Arrow error"))]
51 Arrow {
52 #[snafu(source)]
53 error: arrow_schema::ArrowError,
54 },
55
56 #[snafu(display("Internal error: {}", err_msg))]
57 Internal { err_msg: String },
58
59 #[snafu(display("Unsupported data type: {}, reason: {}", data_type, reason))]
60 UnsupportedDataType {
61 data_type: ConcreteDataType,
62 reason: String,
63 },
64
65 #[snafu(display("Internal IO error"))]
66 InternalIo {
67 #[snafu(source)]
68 error: std::io::Error,
69 },
70
71 #[snafu(display("Tokio IO error: {}", err_msg))]
72 TokioIo {
73 err_msg: String,
74 #[snafu(source)]
75 error: std::io::Error,
76 },
77
78 #[snafu(display("Failed to collect recordbatch"))]
79 CollectRecordbatch {
80 #[snafu(implicit)]
81 location: Location,
82 source: common_recordbatch::error::Error,
83 },
84
85 #[snafu(display("Failed to start HTTP server"))]
86 StartHttp {
87 #[snafu(source)]
88 error: hyper::Error,
89 },
90
91 #[snafu(display("Failed to start gRPC server"))]
92 StartGrpc {
93 #[snafu(source)]
94 error: tonic::transport::Error,
95 },
96
97 #[snafu(display("{} server is already started", server))]
98 AlreadyStarted {
99 server: String,
100 #[snafu(implicit)]
101 location: Location,
102 },
103
104 #[snafu(display("Failed to bind address {}", addr))]
105 TcpBind {
106 addr: SocketAddr,
107 #[snafu(source)]
108 error: std::io::Error,
109 },
110
111 #[snafu(display("Failed to execute query"))]
112 ExecuteQuery {
113 #[snafu(implicit)]
114 location: Location,
115 source: BoxedError,
116 },
117
118 #[snafu(display("Failed to execute plan"))]
119 ExecutePlan {
120 #[snafu(implicit)]
121 location: Location,
122 source: BoxedError,
123 },
124
125 #[snafu(display("Execute gRPC query error"))]
126 ExecuteGrpcQuery {
127 #[snafu(implicit)]
128 location: Location,
129 source: BoxedError,
130 },
131
132 #[snafu(display("Execute gRPC request error"))]
133 ExecuteGrpcRequest {
134 #[snafu(implicit)]
135 location: Location,
136 source: BoxedError,
137 },
138
139 #[snafu(display("Failed to check database validity"))]
140 CheckDatabaseValidity {
141 #[snafu(implicit)]
142 location: Location,
143 source: BoxedError,
144 },
145
146 #[snafu(display("Failed to describe statement"))]
147 DescribeStatement { source: BoxedError },
148
149 #[snafu(display("Pipeline error"))]
150 Pipeline {
151 #[snafu(source)]
152 source: pipeline::error::Error,
153 #[snafu(implicit)]
154 location: Location,
155 },
156
157 #[snafu(display("Not supported: {}", feat))]
158 NotSupported { feat: String },
159
160 #[snafu(display("Invalid request parameter: {}", reason))]
161 InvalidParameter {
162 reason: String,
163 #[snafu(implicit)]
164 location: Location,
165 },
166
167 #[snafu(display("Invalid query: {}", reason))]
168 InvalidQuery {
169 reason: String,
170 #[snafu(implicit)]
171 location: Location,
172 },
173
174 #[snafu(display("Failed to parse query"))]
175 FailedToParseQuery {
176 #[snafu(implicit)]
177 location: Location,
178 source: sql::error::Error,
179 },
180
181 #[snafu(display("Failed to parse InfluxDB line protocol"))]
182 InfluxdbLineProtocol {
183 #[snafu(implicit)]
184 location: Location,
185 #[snafu(source)]
186 error: influxdb_line_protocol::Error,
187 },
188
189 #[snafu(display("Failed to write row"))]
190 RowWriter {
191 #[snafu(implicit)]
192 location: Location,
193 source: common_grpc::error::Error,
194 },
195
196 #[snafu(display("Failed to convert time precision, name: {}", name))]
197 TimePrecision {
198 name: String,
199 #[snafu(implicit)]
200 location: Location,
201 },
202
203 #[snafu(display("Invalid OpenTSDB Json request"))]
204 InvalidOpentsdbJsonRequest {
205 #[snafu(source)]
206 error: serde_json::error::Error,
207 #[snafu(implicit)]
208 location: Location,
209 },
210
211 #[snafu(display("Failed to decode prometheus remote request"))]
212 DecodePromRemoteRequest {
213 #[snafu(implicit)]
214 location: Location,
215 #[snafu(source)]
216 error: prost::DecodeError,
217 },
218
219 #[snafu(display("Failed to decode OTLP request"))]
220 DecodeOtlpRequest {
221 #[snafu(implicit)]
222 location: Location,
223 #[snafu(source)]
224 error: prost::DecodeError,
225 },
226
227 #[snafu(display(
228 "OTLP metric input have incompatible existing tables, please refer to docs for details"
229 ))]
230 OtlpMetricModeIncompatible {
231 #[snafu(implicit)]
232 location: Location,
233 },
234
235 #[snafu(display("Common Meta error"))]
236 CommonMeta {
237 #[snafu(implicit)]
238 location: Location,
239 #[snafu(source)]
240 source: common_meta::error::Error,
241 },
242
243 #[snafu(display("Failed to decompress snappy prometheus remote request"))]
244 DecompressSnappyPromRemoteRequest {
245 #[snafu(implicit)]
246 location: Location,
247 #[snafu(source)]
248 error: snap::Error,
249 },
250
251 #[snafu(display("Failed to decompress zstd prometheus remote request"))]
252 DecompressZstdPromRemoteRequest {
253 #[snafu(implicit)]
254 location: Location,
255 #[snafu(source)]
256 error: std::io::Error,
257 },
258
259 #[snafu(display("Failed to send prometheus remote request"))]
260 SendPromRemoteRequest {
261 #[snafu(implicit)]
262 location: Location,
263 #[snafu(source)]
264 error: reqwest::Error,
265 },
266
267 #[snafu(display("Invalid export metrics config, msg: {}", msg))]
268 InvalidExportMetricsConfig {
269 msg: String,
270 #[snafu(implicit)]
271 location: Location,
272 },
273
274 #[snafu(display("Failed to compress prometheus remote request"))]
275 CompressPromRemoteRequest {
276 #[snafu(implicit)]
277 location: Location,
278 #[snafu(source)]
279 error: snap::Error,
280 },
281
282 #[snafu(display("Invalid prometheus remote request, msg: {}", msg))]
283 InvalidPromRemoteRequest {
284 msg: String,
285 #[snafu(implicit)]
286 location: Location,
287 },
288
289 #[snafu(display("Invalid prometheus remote read query result, msg: {}", msg))]
290 InvalidPromRemoteReadQueryResult {
291 msg: String,
292 #[snafu(implicit)]
293 location: Location,
294 },
295
296 #[snafu(display("Invalid Flight ticket"))]
297 InvalidFlightTicket {
298 #[snafu(source)]
299 error: api::DecodeError,
300 #[snafu(implicit)]
301 location: Location,
302 },
303
304 #[snafu(display("Tls is required for {}, plain connection is rejected", server))]
305 TlsRequired { server: String },
306
307 #[snafu(display("Failed to get user info"))]
308 Auth {
309 #[snafu(implicit)]
310 location: Location,
311 source: auth::error::Error,
312 },
313
314 #[snafu(display("Not found http or grpc authorization header"))]
315 NotFoundAuthHeader {},
316
317 #[snafu(display("Not found influx http authorization info"))]
318 NotFoundInfluxAuth {},
319
320 #[snafu(display("Unsupported http auth scheme, name: {}", name))]
321 UnsupportedAuthScheme { name: String },
322
323 #[snafu(display("Invalid visibility ASCII chars"))]
324 InvalidAuthHeaderInvisibleASCII {
325 #[snafu(source)]
326 error: hyper::header::ToStrError,
327 #[snafu(implicit)]
328 location: Location,
329 },
330
331 #[snafu(display("Invalid utf-8 value"))]
332 InvalidAuthHeaderInvalidUtf8Value {
333 #[snafu(source)]
334 error: FromUtf8Error,
335 #[snafu(implicit)]
336 location: Location,
337 },
338
339 #[snafu(display("Invalid http authorization header"))]
340 InvalidAuthHeader {
341 #[snafu(implicit)]
342 location: Location,
343 },
344
345 #[snafu(display("Invalid base64 value"))]
346 InvalidBase64Value {
347 #[snafu(source)]
348 error: DecodeError,
349 #[snafu(implicit)]
350 location: Location,
351 },
352
353 #[snafu(display("Invalid utf-8 value"))]
354 InvalidUtf8Value {
355 #[snafu(source)]
356 error: FromUtf8Error,
357 #[snafu(implicit)]
358 location: Location,
359 },
360
361 #[snafu(display("Invalid http header value"))]
362 InvalidHeaderValue {
363 #[snafu(source)]
364 error: InvalidHeaderValue,
365 #[snafu(implicit)]
366 location: Location,
367 },
368
369 #[snafu(display("Error accessing catalog"))]
370 Catalog {
371 source: catalog::error::Error,
372 #[snafu(implicit)]
373 location: Location,
374 },
375
376 #[snafu(display("Cannot find requested table: {}.{}.{}", catalog, schema, table))]
377 TableNotFound {
378 catalog: String,
379 schema: String,
380 table: String,
381 #[snafu(implicit)]
382 location: Location,
383 },
384
385 #[cfg(feature = "mem-prof")]
386 #[snafu(display("Failed to dump profile data"))]
387 DumpProfileData {
388 #[snafu(implicit)]
389 location: Location,
390 source: common_mem_prof::error::Error,
391 },
392
393 #[snafu(display("Invalid prepare statement: {}", err_msg))]
394 InvalidPrepareStatement {
395 err_msg: String,
396 #[snafu(implicit)]
397 location: Location,
398 },
399
400 #[snafu(display("Failed to build HTTP response"))]
401 BuildHttpResponse {
402 #[snafu(source)]
403 error: http::Error,
404 #[snafu(implicit)]
405 location: Location,
406 },
407
408 #[snafu(display("Failed to parse PromQL: {query:?}"))]
409 ParsePromQL {
410 query: Box<PromQuery>,
411 #[snafu(implicit)]
412 location: Location,
413 source: query::error::Error,
414 },
415
416 #[snafu(display("Failed to parse timestamp: {}", timestamp))]
417 ParseTimestamp {
418 timestamp: String,
419 #[snafu(implicit)]
420 location: Location,
421 #[snafu(source)]
422 error: query::error::Error,
423 },
424
425 #[snafu(display("{}", reason))]
426 UnexpectedResult {
427 reason: String,
428 #[snafu(implicit)]
429 location: Location,
430 },
431
432 #[snafu(display("Other error"))]
435 Other {
436 source: BoxedError,
437 #[snafu(implicit)]
438 location: Location,
439 },
440
441 #[snafu(display("Failed to join task"))]
442 JoinTask {
443 #[snafu(source)]
444 error: tokio::task::JoinError,
445 #[snafu(implicit)]
446 location: Location,
447 },
448
449 #[cfg(feature = "pprof")]
450 #[snafu(display("Failed to dump pprof data"))]
451 DumpPprof { source: common_pprof::error::Error },
452
453 #[cfg(not(windows))]
454 #[snafu(display("Failed to update jemalloc metrics"))]
455 UpdateJemallocMetrics {
456 #[snafu(source)]
457 error: tikv_jemalloc_ctl::Error,
458 #[snafu(implicit)]
459 location: Location,
460 },
461
462 #[snafu(display("DataFrame operation error"))]
463 DataFrame {
464 #[snafu(source)]
465 error: datafusion::error::DataFusionError,
466 #[snafu(implicit)]
467 location: Location,
468 },
469
470 #[snafu(display("Failed to convert scalar value"))]
471 ConvertScalarValue {
472 source: datatypes::error::Error,
473 #[snafu(implicit)]
474 location: Location,
475 },
476
477 #[snafu(display("Expected type: {:?}, actual: {:?}", expected, actual))]
478 PreparedStmtTypeMismatch {
479 expected: ConcreteDataType,
480 actual: opensrv_mysql::ColumnType,
481 #[snafu(implicit)]
482 location: Location,
483 },
484
485 #[snafu(display(
486 "Column: {}, {} incompatible, expected: {}, actual: {}",
487 column_name,
488 datatype,
489 expected,
490 actual
491 ))]
492 IncompatibleSchema {
493 column_name: String,
494 datatype: String,
495 expected: i32,
496 actual: i32,
497 #[snafu(implicit)]
498 location: Location,
499 },
500
501 #[snafu(display("Failed to convert to json"))]
502 ToJson {
503 #[snafu(source)]
504 error: serde_json::error::Error,
505 #[snafu(implicit)]
506 location: Location,
507 },
508
509 #[snafu(display("Failed to parse payload as json"))]
510 ParseJson {
511 #[snafu(source)]
512 error: serde_json::error::Error,
513 #[snafu(implicit)]
514 location: Location,
515 },
516
517 #[snafu(display("Invalid Loki labels: {}", msg))]
518 InvalidLokiLabels {
519 msg: String,
520 #[snafu(implicit)]
521 location: Location,
522 },
523
524 #[snafu(display("Invalid Loki JSON request: {}", msg))]
525 InvalidLokiPayload {
526 msg: String,
527 #[snafu(implicit)]
528 location: Location,
529 },
530
531 #[snafu(display("Unsupported content type: {:?}", content_type))]
532 UnsupportedContentType {
533 content_type: ContentType,
534 #[snafu(implicit)]
535 location: Location,
536 },
537
538 #[snafu(display("Failed to decode url"))]
539 UrlDecode {
540 #[snafu(source)]
541 error: FromUtf8Error,
542 #[snafu(implicit)]
543 location: Location,
544 },
545
546 #[snafu(display("Failed to convert Mysql value, error: {}", err_msg))]
547 MysqlValueConversion {
548 err_msg: String,
549 #[snafu(implicit)]
550 location: Location,
551 },
552
553 #[snafu(display("Invalid table name"))]
554 InvalidTableName {
555 #[snafu(source)]
556 error: tonic::metadata::errors::ToStrError,
557 #[snafu(implicit)]
558 location: Location,
559 },
560
561 #[snafu(display("Failed to initialize a watcher for file {}", path))]
562 FileWatch {
563 path: String,
564 #[snafu(source)]
565 error: notify::Error,
566 },
567
568 #[snafu(display("Timestamp overflow: {}", error))]
569 TimestampOverflow {
570 error: String,
571 #[snafu(implicit)]
572 location: Location,
573 },
574
575 #[snafu(display("Unsupported json data type for tag: {} {}", key, ty))]
576 UnsupportedJsonDataTypeForTag {
577 key: String,
578 ty: String,
579 #[snafu(implicit)]
580 location: Location,
581 },
582
583 #[snafu(display("Convert SQL value error"))]
584 ConvertSqlValue {
585 source: datatypes::error::Error,
586 #[snafu(implicit)]
587 location: Location,
588 },
589
590 #[snafu(display("Prepare statement not found: {}", name))]
591 PrepareStatementNotFound {
592 name: String,
593 #[snafu(implicit)]
594 location: Location,
595 },
596
597 #[snafu(display("In-flight write bytes exceeded the maximum limit"))]
598 InFlightWriteBytesExceeded {
599 #[snafu(implicit)]
600 location: Location,
601 },
602
603 #[snafu(display("Invalid elasticsearch input, reason: {}", reason))]
604 InvalidElasticsearchInput {
605 reason: String,
606 #[snafu(implicit)]
607 location: Location,
608 },
609
610 #[snafu(display("Invalid Jaeger query, reason: {}", reason))]
611 InvalidJaegerQuery {
612 reason: String,
613 #[snafu(implicit)]
614 location: Location,
615 },
616
617 #[snafu(display("DataFusion error"))]
618 DataFusion {
619 #[snafu(source)]
620 error: DataFusionError,
621 #[snafu(implicit)]
622 location: Location,
623 },
624
625 #[snafu(display("Overflow while casting `{:?}` to Interval", val))]
626 DurationOverflow { val: Duration },
627
628 #[snafu(display("Failed to handle otel-arrow request, error message: {}", err_msg))]
629 HandleOtelArrowRequest {
630 err_msg: String,
631 #[snafu(implicit)]
632 location: Location,
633 },
634
635 #[snafu(display("Unknown hint: {}", hint))]
636 UnknownHint { hint: String },
637
638 #[snafu(display("Query has been cancelled"))]
639 Cancelled {
640 #[snafu(implicit)]
641 location: Location,
642 },
643}
644
645pub type Result<T, E = Error> = std::result::Result<T, E>;
646
647impl ErrorExt for Error {
648 fn status_code(&self) -> StatusCode {
649 use Error::*;
650 match self {
651 Internal { .. }
652 | InternalIo { .. }
653 | TokioIo { .. }
654 | StartHttp { .. }
655 | StartGrpc { .. }
656 | TcpBind { .. }
657 | SendPromRemoteRequest { .. }
658 | BuildHttpResponse { .. }
659 | Arrow { .. }
660 | FileWatch { .. } => StatusCode::Internal,
661
662 AddressBind { .. }
663 | AlreadyStarted { .. }
664 | InvalidPromRemoteReadQueryResult { .. }
665 | OtlpMetricModeIncompatible { .. } => StatusCode::IllegalState,
666
667 UnsupportedDataType { .. } => StatusCode::Unsupported,
668
669 #[cfg(not(windows))]
670 UpdateJemallocMetrics { .. } => StatusCode::Internal,
671
672 CollectRecordbatch { .. } => StatusCode::EngineExecuteQuery,
673
674 ExecuteQuery { source, .. }
675 | ExecutePlan { source, .. }
676 | ExecuteGrpcQuery { source, .. }
677 | ExecuteGrpcRequest { source, .. }
678 | CheckDatabaseValidity { source, .. } => source.status_code(),
679
680 Pipeline { source, .. } => source.status_code(),
681 CommonMeta { source, .. } => source.status_code(),
682
683 NotSupported { .. }
684 | InvalidParameter { .. }
685 | InvalidQuery { .. }
686 | InfluxdbLineProtocol { .. }
687 | InvalidOpentsdbJsonRequest { .. }
688 | DecodePromRemoteRequest { .. }
689 | DecodeOtlpRequest { .. }
690 | CompressPromRemoteRequest { .. }
691 | DecompressSnappyPromRemoteRequest { .. }
692 | DecompressZstdPromRemoteRequest { .. }
693 | InvalidPromRemoteRequest { .. }
694 | InvalidExportMetricsConfig { .. }
695 | InvalidFlightTicket { .. }
696 | InvalidPrepareStatement { .. }
697 | DataFrame { .. }
698 | PreparedStmtTypeMismatch { .. }
699 | TimePrecision { .. }
700 | UrlDecode { .. }
701 | IncompatibleSchema { .. }
702 | MysqlValueConversion { .. }
703 | ParseJson { .. }
704 | InvalidLokiLabels { .. }
705 | InvalidLokiPayload { .. }
706 | UnsupportedContentType { .. }
707 | TimestampOverflow { .. }
708 | UnsupportedJsonDataTypeForTag { .. }
709 | InvalidTableName { .. }
710 | PrepareStatementNotFound { .. }
711 | FailedToParseQuery { .. }
712 | InvalidElasticsearchInput { .. }
713 | InvalidJaegerQuery { .. }
714 | ParseTimestamp { .. }
715 | UnknownHint { .. } => StatusCode::InvalidArguments,
716
717 Catalog { source, .. } => source.status_code(),
718 RowWriter { source, .. } => source.status_code(),
719
720 TlsRequired { .. } => StatusCode::Unknown,
721 Auth { source, .. } => source.status_code(),
722 DescribeStatement { source } => source.status_code(),
723
724 NotFoundAuthHeader { .. } | NotFoundInfluxAuth { .. } => StatusCode::AuthHeaderNotFound,
725 InvalidAuthHeaderInvisibleASCII { .. }
726 | UnsupportedAuthScheme { .. }
727 | InvalidAuthHeader { .. }
728 | InvalidBase64Value { .. }
729 | InvalidAuthHeaderInvalidUtf8Value { .. } => StatusCode::InvalidAuthHeader,
730
731 TableNotFound { .. } => StatusCode::TableNotFound,
732
733 #[cfg(feature = "mem-prof")]
734 DumpProfileData { source, .. } => source.status_code(),
735
736 InvalidUtf8Value { .. } | InvalidHeaderValue { .. } => StatusCode::InvalidArguments,
737
738 ParsePromQL { source, .. } => source.status_code(),
739 Other { source, .. } => source.status_code(),
740
741 UnexpectedResult { .. } => StatusCode::Unexpected,
742
743 JoinTask { error, .. } => {
744 if error.is_cancelled() {
745 StatusCode::Cancelled
746 } else if error.is_panic() {
747 StatusCode::Unexpected
748 } else {
749 StatusCode::Unknown
750 }
751 }
752
753 #[cfg(feature = "pprof")]
754 DumpPprof { source, .. } => source.status_code(),
755
756 ConvertScalarValue { source, .. } => source.status_code(),
757
758 ToJson { .. } | DataFusion { .. } => StatusCode::Internal,
759
760 ConvertSqlValue { source, .. } => source.status_code(),
761
762 InFlightWriteBytesExceeded { .. } => StatusCode::RateLimited,
763
764 DurationOverflow { .. } => StatusCode::InvalidArguments,
765
766 HandleOtelArrowRequest { .. } => StatusCode::Internal,
767
768 Cancelled { .. } => StatusCode::Cancelled,
769 }
770 }
771
772 fn as_any(&self) -> &dyn Any {
773 self
774 }
775}
776
777define_into_tonic_status!(Error);
778
779impl From<std::io::Error> for Error {
780 fn from(e: std::io::Error) -> Self {
781 Error::InternalIo { error: e }
782 }
783}
784
785fn log_error_if_necessary(error: &Error) {
786 if error.status_code().should_log_error() {
787 error!(error; "Failed to handle HTTP request ");
788 } else {
789 warn!(error; "Failed to handle HTTP request ");
790 }
791}
792
793impl IntoResponse for Error {
794 fn into_response(self) -> Response {
795 let error_msg = self.output_msg();
796 let status = status_code_to_http_status(&self.status_code());
797
798 log_error_if_necessary(&self);
799
800 let body = Json(json!({
801 "error": error_msg,
802 }));
803 (status, body).into_response()
804 }
805}
806
807pub fn status_code_to_http_status(status_code: &StatusCode) -> HttpStatusCode {
809 match status_code {
810 StatusCode::Success => HttpStatusCode::OK,
811
812 StatusCode::Cancelled | StatusCode::DeadlineExceeded => HttpStatusCode::GATEWAY_TIMEOUT,
815
816 StatusCode::Unsupported
817 | StatusCode::InvalidArguments
818 | StatusCode::InvalidSyntax
819 | StatusCode::RequestOutdated
820 | StatusCode::RegionAlreadyExists
821 | StatusCode::TableColumnExists
822 | StatusCode::TableAlreadyExists
823 | StatusCode::RegionNotFound
824 | StatusCode::DatabaseNotFound
825 | StatusCode::TableNotFound
826 | StatusCode::TableColumnNotFound
827 | StatusCode::PlanQuery
828 | StatusCode::DatabaseAlreadyExists
829 | StatusCode::TriggerAlreadyExists
830 | StatusCode::TriggerNotFound
831 | StatusCode::FlowNotFound
832 | StatusCode::FlowAlreadyExists => HttpStatusCode::BAD_REQUEST,
833
834 StatusCode::AuthHeaderNotFound
835 | StatusCode::InvalidAuthHeader
836 | StatusCode::UserNotFound
837 | StatusCode::UnsupportedPasswordType
838 | StatusCode::UserPasswordMismatch
839 | StatusCode::RegionReadonly => HttpStatusCode::UNAUTHORIZED,
840
841 StatusCode::PermissionDenied | StatusCode::AccessDenied => HttpStatusCode::FORBIDDEN,
842
843 StatusCode::RateLimited => HttpStatusCode::TOO_MANY_REQUESTS,
844
845 StatusCode::RegionNotReady
846 | StatusCode::TableUnavailable
847 | StatusCode::RegionBusy
848 | StatusCode::StorageUnavailable
849 | StatusCode::External => HttpStatusCode::SERVICE_UNAVAILABLE,
850
851 StatusCode::Internal
852 | StatusCode::Unexpected
853 | StatusCode::IllegalState
854 | StatusCode::Unknown
855 | StatusCode::RuntimeResourcesExhausted
856 | StatusCode::EngineExecuteQuery => HttpStatusCode::INTERNAL_SERVER_ERROR,
857 }
858}