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::{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    // 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("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
807/// Converts [StatusCode] to [HttpStatusCode].
808pub fn status_code_to_http_status(status_code: &StatusCode) -> HttpStatusCode {
809    match status_code {
810        StatusCode::Success => HttpStatusCode::OK,
811
812        // When a request is cancelled by the client (e.g., by a client side timeout),
813        // we should return a gateway timeout status code to the external client.
814        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}