servers/
error.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use 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::{Json, http};
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    // this error is used for custom error mapping
433    // please do not delete it
434    #[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("Invalid elasticsearch input, reason: {}", reason))]
598    InvalidElasticsearchInput {
599        reason: String,
600        #[snafu(implicit)]
601        location: Location,
602    },
603
604    #[snafu(display("Invalid Jaeger query, reason: {}", reason))]
605    InvalidJaegerQuery {
606        reason: String,
607        #[snafu(implicit)]
608        location: Location,
609    },
610
611    #[snafu(display("DataFusion error"))]
612    DataFusion {
613        #[snafu(source)]
614        error: DataFusionError,
615        #[snafu(implicit)]
616        location: Location,
617    },
618
619    #[snafu(display("Overflow while casting `{:?}` to Interval", val))]
620    DurationOverflow { val: Duration },
621
622    #[snafu(display("Failed to handle otel-arrow request, error message: {}", err_msg))]
623    HandleOtelArrowRequest {
624        err_msg: String,
625        #[snafu(implicit)]
626        location: Location,
627    },
628
629    #[snafu(display("Unknown hint: {}", hint))]
630    UnknownHint { hint: String },
631
632    #[snafu(display("Query has been cancelled"))]
633    Cancelled {
634        #[snafu(implicit)]
635        location: Location,
636    },
637}
638
639pub type Result<T, E = Error> = std::result::Result<T, E>;
640
641impl ErrorExt for Error {
642    fn status_code(&self) -> StatusCode {
643        use Error::*;
644        match self {
645            Internal { .. }
646            | InternalIo { .. }
647            | TokioIo { .. }
648            | StartHttp { .. }
649            | StartGrpc { .. }
650            | TcpBind { .. }
651            | SendPromRemoteRequest { .. }
652            | BuildHttpResponse { .. }
653            | Arrow { .. }
654            | FileWatch { .. } => StatusCode::Internal,
655
656            AddressBind { .. }
657            | AlreadyStarted { .. }
658            | InvalidPromRemoteReadQueryResult { .. }
659            | OtlpMetricModeIncompatible { .. } => StatusCode::IllegalState,
660
661            UnsupportedDataType { .. } => StatusCode::Unsupported,
662
663            #[cfg(not(windows))]
664            UpdateJemallocMetrics { .. } => StatusCode::Internal,
665
666            CollectRecordbatch { .. } => StatusCode::EngineExecuteQuery,
667
668            ExecuteQuery { source, .. }
669            | ExecutePlan { source, .. }
670            | ExecuteGrpcQuery { source, .. }
671            | ExecuteGrpcRequest { source, .. }
672            | CheckDatabaseValidity { source, .. } => source.status_code(),
673
674            Pipeline { source, .. } => source.status_code(),
675            CommonMeta { source, .. } => source.status_code(),
676
677            NotSupported { .. }
678            | InvalidParameter { .. }
679            | InvalidQuery { .. }
680            | InfluxdbLineProtocol { .. }
681            | InvalidOpentsdbJsonRequest { .. }
682            | DecodePromRemoteRequest { .. }
683            | DecodeOtlpRequest { .. }
684            | CompressPromRemoteRequest { .. }
685            | DecompressSnappyPromRemoteRequest { .. }
686            | DecompressZstdPromRemoteRequest { .. }
687            | InvalidPromRemoteRequest { .. }
688            | InvalidExportMetricsConfig { .. }
689            | InvalidFlightTicket { .. }
690            | InvalidPrepareStatement { .. }
691            | DataFrame { .. }
692            | PreparedStmtTypeMismatch { .. }
693            | TimePrecision { .. }
694            | UrlDecode { .. }
695            | IncompatibleSchema { .. }
696            | MysqlValueConversion { .. }
697            | ParseJson { .. }
698            | InvalidLokiLabels { .. }
699            | InvalidLokiPayload { .. }
700            | UnsupportedContentType { .. }
701            | TimestampOverflow { .. }
702            | UnsupportedJsonDataTypeForTag { .. }
703            | InvalidTableName { .. }
704            | PrepareStatementNotFound { .. }
705            | FailedToParseQuery { .. }
706            | InvalidElasticsearchInput { .. }
707            | InvalidJaegerQuery { .. }
708            | ParseTimestamp { .. }
709            | UnknownHint { .. } => StatusCode::InvalidArguments,
710
711            Catalog { source, .. } => source.status_code(),
712            RowWriter { source, .. } => source.status_code(),
713
714            TlsRequired { .. } => StatusCode::Unknown,
715            Auth { source, .. } => source.status_code(),
716            DescribeStatement { source } => source.status_code(),
717
718            NotFoundAuthHeader { .. } | NotFoundInfluxAuth { .. } => StatusCode::AuthHeaderNotFound,
719            InvalidAuthHeaderInvisibleASCII { .. }
720            | UnsupportedAuthScheme { .. }
721            | InvalidAuthHeader { .. }
722            | InvalidBase64Value { .. }
723            | InvalidAuthHeaderInvalidUtf8Value { .. } => StatusCode::InvalidAuthHeader,
724
725            TableNotFound { .. } => StatusCode::TableNotFound,
726
727            #[cfg(feature = "mem-prof")]
728            DumpProfileData { source, .. } => source.status_code(),
729
730            InvalidUtf8Value { .. } | InvalidHeaderValue { .. } => StatusCode::InvalidArguments,
731
732            ParsePromQL { source, .. } => source.status_code(),
733            Other { source, .. } => source.status_code(),
734
735            UnexpectedResult { .. } => StatusCode::Unexpected,
736
737            JoinTask { error, .. } => {
738                if error.is_cancelled() {
739                    StatusCode::Cancelled
740                } else if error.is_panic() {
741                    StatusCode::Unexpected
742                } else {
743                    StatusCode::Unknown
744                }
745            }
746
747            #[cfg(feature = "pprof")]
748            DumpPprof { source, .. } => source.status_code(),
749
750            ConvertScalarValue { source, .. } => source.status_code(),
751
752            ToJson { .. } | DataFusion { .. } => StatusCode::Internal,
753
754            ConvertSqlValue { source, .. } => source.status_code(),
755
756            DurationOverflow { .. } => StatusCode::InvalidArguments,
757
758            HandleOtelArrowRequest { .. } => StatusCode::Internal,
759
760            Cancelled { .. } => StatusCode::Cancelled,
761        }
762    }
763
764    fn as_any(&self) -> &dyn Any {
765        self
766    }
767}
768
769define_into_tonic_status!(Error);
770
771impl From<std::io::Error> for Error {
772    fn from(e: std::io::Error) -> Self {
773        Error::InternalIo { error: e }
774    }
775}
776
777fn log_error_if_necessary(error: &Error) {
778    if error.status_code().should_log_error() {
779        error!(error; "Failed to handle HTTP request ");
780    } else {
781        warn!(error; "Failed to handle HTTP request ");
782    }
783}
784
785impl IntoResponse for Error {
786    fn into_response(self) -> Response {
787        let error_msg = self.output_msg();
788        let status = status_code_to_http_status(&self.status_code());
789
790        log_error_if_necessary(&self);
791
792        let body = Json(json!({
793            "error": error_msg,
794        }));
795        (status, body).into_response()
796    }
797}
798
799/// Converts [StatusCode] to [HttpStatusCode].
800pub fn status_code_to_http_status(status_code: &StatusCode) -> HttpStatusCode {
801    match status_code {
802        StatusCode::Success => HttpStatusCode::OK,
803
804        // When a request is cancelled by the client (e.g., by a client side timeout),
805        // we should return a gateway timeout status code to the external client.
806        StatusCode::Cancelled | StatusCode::DeadlineExceeded => HttpStatusCode::GATEWAY_TIMEOUT,
807
808        StatusCode::Unsupported
809        | StatusCode::InvalidArguments
810        | StatusCode::InvalidSyntax
811        | StatusCode::RequestOutdated
812        | StatusCode::RegionAlreadyExists
813        | StatusCode::TableColumnExists
814        | StatusCode::TableAlreadyExists
815        | StatusCode::RegionNotFound
816        | StatusCode::DatabaseNotFound
817        | StatusCode::TableNotFound
818        | StatusCode::TableColumnNotFound
819        | StatusCode::PlanQuery
820        | StatusCode::DatabaseAlreadyExists
821        | StatusCode::TriggerAlreadyExists
822        | StatusCode::TriggerNotFound
823        | StatusCode::FlowNotFound
824        | StatusCode::FlowAlreadyExists => HttpStatusCode::BAD_REQUEST,
825
826        StatusCode::AuthHeaderNotFound
827        | StatusCode::InvalidAuthHeader
828        | StatusCode::UserNotFound
829        | StatusCode::UnsupportedPasswordType
830        | StatusCode::UserPasswordMismatch
831        | StatusCode::RegionReadonly => HttpStatusCode::UNAUTHORIZED,
832
833        StatusCode::PermissionDenied | StatusCode::AccessDenied => HttpStatusCode::FORBIDDEN,
834
835        StatusCode::RateLimited => HttpStatusCode::TOO_MANY_REQUESTS,
836
837        StatusCode::RegionNotReady
838        | StatusCode::TableUnavailable
839        | StatusCode::RegionBusy
840        | StatusCode::StorageUnavailable
841        | StatusCode::External => HttpStatusCode::SERVICE_UNAVAILABLE,
842
843        StatusCode::Internal
844        | StatusCode::Unexpected
845        | StatusCode::IllegalState
846        | StatusCode::Unknown
847        | StatusCode::RuntimeResourcesExhausted
848        | StatusCode::EngineExecuteQuery => HttpStatusCode::INTERNAL_SERVER_ERROR,
849    }
850}