1use 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 #[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
936pub fn status_code_to_http_status(status_code: &StatusCode) -> HttpStatusCode {
938 match status_code {
939 StatusCode::Success => HttpStatusCode::OK,
940
941 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}