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