Skip to main content

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