Skip to main content

common_meta/
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::str::Utf8Error;
16use std::sync::Arc;
17
18use common_error::ext::{BoxedError, ErrorExt, RetryHint};
19use common_error::status_code::StatusCode;
20use common_macro::stack_trace_debug;
21use common_procedure::ProcedureId;
22use common_wal::kafka::rskafka_client_error_to_retry_hint;
23use object_store::error::retry_hint_from_opendal_error;
24use serde_json::error::Error as JsonError;
25use snafu::{Location, Snafu};
26use store_api::storage::RegionId;
27use table::metadata::TableId;
28
29use crate::DatanodeId;
30use crate::peer::Peer;
31
32mod retry_hint;
33
34pub use retry_hint::retry_hint_from_etcd_error;
35#[cfg(feature = "mysql_kvbackend")]
36pub use retry_hint::retry_hint_from_sqlx_error;
37#[cfg(feature = "pg_kvbackend")]
38pub use retry_hint::{retry_hint_from_postgres_error, retry_hint_from_postgres_pool_error};
39
40#[derive(Snafu)]
41#[snafu(visibility(pub))]
42#[stack_trace_debug]
43pub enum Error {
44    #[snafu(display("Empty key is not allowed"))]
45    EmptyKey {
46        #[snafu(implicit)]
47        location: Location,
48    },
49
50    #[snafu(display(
51        "Another procedure is operating the region: {} on peer: {}",
52        region_id,
53        peer_id
54    ))]
55    RegionOperatingRace {
56        #[snafu(implicit)]
57        location: Location,
58        peer_id: DatanodeId,
59        region_id: RegionId,
60    },
61
62    #[snafu(display("Failed to connect to Etcd"))]
63    ConnectEtcd {
64        #[snafu(source)]
65        error: etcd_client::Error,
66        #[snafu(implicit)]
67        location: Location,
68    },
69
70    #[snafu(display("Failed to execute via Etcd"))]
71    EtcdFailed {
72        #[snafu(source)]
73        error: etcd_client::Error,
74        #[snafu(implicit)]
75        location: Location,
76    },
77
78    #[snafu(display("Failed to execute {} txn operations via Etcd", max_operations))]
79    EtcdTxnFailed {
80        max_operations: usize,
81        #[snafu(source)]
82        error: etcd_client::Error,
83        #[snafu(implicit)]
84        location: Location,
85    },
86
87    #[snafu(display("Failed to get sequence: {}", err_msg))]
88    NextSequence {
89        err_msg: String,
90        #[snafu(implicit)]
91        location: Location,
92    },
93
94    #[snafu(display("Unexpected sequence value: {}", err_msg))]
95    UnexpectedSequenceValue {
96        err_msg: String,
97        #[snafu(implicit)]
98        location: Location,
99    },
100
101    #[snafu(display("Table info not found: {}", table))]
102    TableInfoNotFound {
103        table: String,
104        #[snafu(implicit)]
105        location: Location,
106    },
107
108    #[snafu(display("Failed to register procedure loader, type name: {}", type_name))]
109    RegisterProcedureLoader {
110        type_name: String,
111        #[snafu(implicit)]
112        location: Location,
113        source: common_procedure::error::Error,
114    },
115
116    #[snafu(display("Failed to register repartition procedure loader"))]
117    RegisterRepartitionProcedureLoader {
118        #[snafu(implicit)]
119        location: Location,
120        source: BoxedError,
121    },
122
123    #[snafu(display("Failed to create repartition procedure"))]
124    CreateRepartitionProcedure {
125        source: BoxedError,
126        #[snafu(implicit)]
127        location: Location,
128    },
129
130    #[snafu(display("Failed to persist the repartition GC requirement"))]
131    PersistRepartitionGcRequirement {
132        source: BoxedError,
133        #[snafu(implicit)]
134        location: Location,
135    },
136
137    #[snafu(display("Failed to submit procedure"))]
138    SubmitProcedure {
139        #[snafu(implicit)]
140        location: Location,
141        source: common_procedure::Error,
142    },
143
144    #[snafu(display("Failed to query procedure"))]
145    QueryProcedure {
146        #[snafu(implicit)]
147        location: Location,
148        source: common_procedure::Error,
149    },
150
151    #[snafu(display("Procedure not found: {pid}"))]
152    ProcedureNotFound {
153        #[snafu(implicit)]
154        location: Location,
155        pid: String,
156    },
157
158    #[snafu(display("Failed to parse procedure id: {key}"))]
159    ParseProcedureId {
160        #[snafu(implicit)]
161        location: Location,
162        key: String,
163        #[snafu(source)]
164        error: common_procedure::ParseIdError,
165    },
166
167    #[snafu(display("Unsupported operation {}", operation))]
168    Unsupported {
169        operation: String,
170        #[snafu(implicit)]
171        location: Location,
172    },
173
174    #[snafu(display("Trying to write to a read-only kv backend: {}", name))]
175    ReadOnlyKvBackend {
176        name: String,
177        #[snafu(implicit)]
178        location: Location,
179    },
180
181    #[snafu(display("Failed to get procedure state receiver, procedure id: {procedure_id}"))]
182    ProcedureStateReceiver {
183        procedure_id: ProcedureId,
184        #[snafu(implicit)]
185        location: Location,
186        source: common_procedure::Error,
187    },
188
189    #[snafu(display("Procedure state receiver not found: {procedure_id}"))]
190    ProcedureStateReceiverNotFound {
191        procedure_id: ProcedureId,
192        #[snafu(implicit)]
193        location: Location,
194    },
195
196    #[snafu(display("Failed to wait procedure done"))]
197    WaitProcedure {
198        #[snafu(implicit)]
199        location: Location,
200        source: common_procedure::Error,
201    },
202
203    #[snafu(display("Failed to start procedure manager"))]
204    StartProcedureManager {
205        #[snafu(implicit)]
206        location: Location,
207        source: common_procedure::Error,
208    },
209
210    #[snafu(display("Failed to stop procedure manager"))]
211    StopProcedureManager {
212        #[snafu(implicit)]
213        location: Location,
214        source: common_procedure::Error,
215    },
216
217    #[snafu(display(
218        "Failed to get procedure output, procedure id: {procedure_id}, error: {err_msg}"
219    ))]
220    ProcedureOutput {
221        procedure_id: String,
222        err_msg: String,
223        #[snafu(implicit)]
224        location: Location,
225    },
226
227    #[snafu(display("Primary key '{key}' not found when creating region request"))]
228    PrimaryKeyNotFound {
229        key: String,
230        #[snafu(implicit)]
231        location: Location,
232    },
233
234    #[snafu(display("Failed to build table meta for table: {}", table_name))]
235    BuildTableMeta {
236        table_name: String,
237        #[snafu(source)]
238        error: table::metadata::TableMetaBuilderError,
239        #[snafu(implicit)]
240        location: Location,
241    },
242
243    #[snafu(display("Table occurs error"))]
244    Table {
245        #[snafu(implicit)]
246        location: Location,
247        source: table::error::Error,
248    },
249
250    #[snafu(display("Failed to find table route for table id {}", table_id))]
251    TableRouteNotFound {
252        table_id: TableId,
253        #[snafu(implicit)]
254        location: Location,
255    },
256
257    #[snafu(display("Failed to find table repartition metadata for table id {}", table_id))]
258    TableRepartNotFound {
259        table_id: TableId,
260        #[snafu(implicit)]
261        location: Location,
262    },
263
264    #[snafu(display("Failed to decode protobuf"))]
265    DecodeProto {
266        #[snafu(implicit)]
267        location: Location,
268        #[snafu(source)]
269        error: prost::DecodeError,
270    },
271
272    #[snafu(display("Failed to decode packed file references"))]
273    DecodePackedFileRefs {
274        #[snafu(implicit)]
275        location: Location,
276        #[snafu(source)]
277        error: base64::DecodeError,
278    },
279
280    #[snafu(display("Invalid packed file references framing"))]
281    InvalidPackedFileRefs {
282        #[snafu(implicit)]
283        location: Location,
284    },
285
286    #[snafu(display("Failed to encode object into json"))]
287    EncodeJson {
288        #[snafu(implicit)]
289        location: Location,
290        #[snafu(source)]
291        error: JsonError,
292    },
293
294    #[snafu(display("Failed to decode object from json"))]
295    DecodeJson {
296        #[snafu(implicit)]
297        location: Location,
298        #[snafu(source)]
299        error: JsonError,
300    },
301
302    #[snafu(display("Failed to serialize to json: {}", input))]
303    SerializeToJson {
304        input: String,
305        #[snafu(source)]
306        error: serde_json::error::Error,
307        #[snafu(implicit)]
308        location: Location,
309    },
310
311    #[snafu(display("Failed to deserialize from json: {}", input))]
312    DeserializeFromJson {
313        input: String,
314        #[snafu(source)]
315        error: serde_json::error::Error,
316        #[snafu(implicit)]
317        location: Location,
318    },
319
320    #[snafu(display("Payload not exist"))]
321    PayloadNotExist {
322        #[snafu(implicit)]
323        location: Location,
324    },
325
326    #[snafu(display("Failed to serde json"))]
327    SerdeJson {
328        #[snafu(source)]
329        error: serde_json::error::Error,
330        #[snafu(implicit)]
331        location: Location,
332    },
333
334    #[snafu(display("Failed to parse value {} into key {}", value, key))]
335    ParseOption {
336        key: String,
337        value: String,
338        #[snafu(implicit)]
339        location: Location,
340    },
341
342    #[snafu(display(
343        "Conflicting schema options: {}={} and {}={}",
344        first_key,
345        first_value,
346        second_key,
347        second_value
348    ))]
349    ConflictingSchemaOptions {
350        first_key: String,
351        first_value: String,
352        second_key: String,
353        second_value: String,
354        #[snafu(implicit)]
355        location: Location,
356    },
357
358    #[snafu(display("Illegal state from server, code: {}, error: {}", code, err_msg))]
359    IllegalServerState {
360        code: i32,
361        err_msg: String,
362        #[snafu(implicit)]
363        location: Location,
364    },
365
366    #[snafu(display("Failed to convert alter table request"))]
367    ConvertAlterTableRequest {
368        source: common_grpc_expr::error::Error,
369        #[snafu(implicit)]
370        location: Location,
371    },
372
373    #[snafu(display("Invalid protobuf message: {err_msg}"))]
374    InvalidProtoMsg {
375        err_msg: String,
376        #[snafu(implicit)]
377        location: Location,
378    },
379
380    #[snafu(display("Unexpected: {err_msg}"))]
381    Unexpected {
382        err_msg: String,
383        #[snafu(implicit)]
384        location: Location,
385    },
386
387    #[snafu(display("Metasrv election has no leader at this moment"))]
388    ElectionNoLeader {
389        #[snafu(implicit)]
390        location: Location,
391    },
392
393    #[snafu(display("Metasrv election leader lease expired"))]
394    ElectionLeaderLeaseExpired {
395        #[snafu(implicit)]
396        location: Location,
397    },
398
399    #[snafu(display("Metasrv election leader lease changed during election"))]
400    ElectionLeaderLeaseChanged {
401        #[snafu(implicit)]
402        location: Location,
403    },
404
405    #[snafu(display("Table already exists, table: {}", table_name))]
406    TableAlreadyExists {
407        table_name: String,
408        #[snafu(implicit)]
409        location: Location,
410    },
411
412    #[snafu(display(
413        "Cannot drop table '{}': an older tombstone already uses the same full name",
414        table_name
415    ))]
416    /// Raised when a live table is recreated with a name still reserved by an older tombstone.
417    TableNameTombstoneConflict {
418        table_name: String,
419        existing_table_id: TableId,
420        dropping_table_id: TableId,
421        #[snafu(implicit)]
422        location: Location,
423    },
424
425    #[snafu(display("View already exists, view: {}", view_name))]
426    ViewAlreadyExists {
427        view_name: String,
428        #[snafu(implicit)]
429        location: Location,
430    },
431
432    #[snafu(display("Flow already exists: {}", flow_name))]
433    FlowAlreadyExists {
434        flow_name: String,
435        #[snafu(implicit)]
436        location: Location,
437    },
438
439    #[snafu(display("Schema already exists, catalog:{}, schema: {}", catalog, schema))]
440    SchemaAlreadyExists {
441        catalog: String,
442        schema: String,
443        #[snafu(implicit)]
444        location: Location,
445    },
446
447    #[snafu(display("Failed to convert raw key to str"))]
448    ConvertRawKey {
449        #[snafu(implicit)]
450        location: Location,
451        #[snafu(source)]
452        error: Utf8Error,
453    },
454
455    #[snafu(display("Table not found: '{}'", table_name))]
456    TableNotFound {
457        table_name: String,
458        #[snafu(implicit)]
459        location: Location,
460    },
461
462    #[snafu(display("Region not found: {}", region_id))]
463    RegionNotFound {
464        region_id: RegionId,
465        #[snafu(implicit)]
466        location: Location,
467    },
468
469    #[snafu(display("View not found: '{}'", view_name))]
470    ViewNotFound {
471        view_name: String,
472        #[snafu(implicit)]
473        location: Location,
474    },
475
476    #[snafu(display("Flow not found: '{}'", flow_name))]
477    FlowNotFound {
478        flow_name: String,
479        #[snafu(implicit)]
480        location: Location,
481    },
482
483    #[snafu(display("Flow route not found: '{}'", flow_name))]
484    FlowRouteNotFound {
485        flow_name: String,
486        #[snafu(implicit)]
487        location: Location,
488    },
489
490    #[snafu(display("Schema nod found, schema: {}", table_schema))]
491    SchemaNotFound {
492        table_schema: String,
493        #[snafu(implicit)]
494        location: Location,
495    },
496
497    #[snafu(display("Catalog not found, catalog: {}", catalog))]
498    CatalogNotFound {
499        catalog: String,
500        #[snafu(implicit)]
501        location: Location,
502    },
503
504    #[snafu(display("Invalid metadata, err: {}", err_msg))]
505    InvalidMetadata {
506        err_msg: String,
507        #[snafu(implicit)]
508        location: Location,
509    },
510
511    #[snafu(display("Invalid view info, err: {}", err_msg))]
512    InvalidViewInfo {
513        err_msg: String,
514        #[snafu(implicit)]
515        location: Location,
516    },
517
518    #[snafu(display("Invalid SQL, error: {err_msg}"))]
519    InvalidFlowOption {
520        err_msg: String,
521        #[snafu(implicit)]
522        location: Location,
523    },
524
525    #[snafu(display("Invalid flow request body: {:?}", body))]
526    InvalidFlowRequestBody {
527        body: Box<Option<api::v1::flow::flow_request::Body>>,
528        #[snafu(implicit)]
529        location: Location,
530    },
531
532    #[snafu(display("Failed to get kv cache, err: {}", err_msg))]
533    GetKvCache { err_msg: String },
534
535    #[snafu(display("Get null from cache, key: {}", key))]
536    CacheNotGet {
537        key: String,
538        #[snafu(implicit)]
539        location: Location,
540    },
541
542    #[snafu(display("Etcd txn error: {err_msg}"))]
543    EtcdTxnOpResponse {
544        err_msg: String,
545        #[snafu(implicit)]
546        location: Location,
547    },
548
549    #[snafu(display("External error"))]
550    External {
551        #[snafu(implicit)]
552        location: Location,
553        source: BoxedError,
554    },
555
556    #[snafu(display("The response exceeded size limit"))]
557    ResponseExceededSizeLimit {
558        #[snafu(implicit)]
559        location: Location,
560        source: BoxedError,
561    },
562
563    #[snafu(display("Invalid heartbeat response"))]
564    InvalidHeartbeatResponse {
565        #[snafu(implicit)]
566        location: Location,
567    },
568
569    #[snafu(display("Failed to operate on datanode: {}", peer))]
570    OperateDatanode {
571        #[snafu(implicit)]
572        location: Location,
573        peer: Peer,
574        source: BoxedError,
575    },
576
577    #[snafu(display("Retry later"))]
578    RetryLater {
579        source: BoxedError,
580        clean_poisons: bool,
581    },
582
583    #[snafu(display("Abort procedure"))]
584    AbortProcedure {
585        #[snafu(implicit)]
586        location: Location,
587        source: BoxedError,
588        clean_poisons: bool,
589    },
590
591    #[snafu(display("Failed to serialize WAL options for region: {region_id}"))]
592    SerializeWalOptions {
593        region_id: RegionId,
594        #[snafu(source)]
595        error: serde_json::Error,
596        #[snafu(implicit)]
597        location: Location,
598    },
599
600    #[snafu(display("Invalid number of topics {}", num_topics))]
601    InvalidNumTopics {
602        num_topics: usize,
603        #[snafu(implicit)]
604        location: Location,
605    },
606
607    #[snafu(display(
608        "Failed to build a Kafka client, broker endpoints: {:?}",
609        broker_endpoints
610    ))]
611    BuildKafkaClient {
612        broker_endpoints: Vec<String>,
613        #[snafu(implicit)]
614        location: Location,
615        #[snafu(source)]
616        error: rskafka::client::error::Error,
617    },
618
619    #[snafu(display("Failed to create TLS Config"))]
620    TlsConfig {
621        #[snafu(implicit)]
622        location: Location,
623        source: common_wal::error::Error,
624    },
625
626    #[snafu(display("Failed to build a Kafka controller client"))]
627    BuildKafkaCtrlClient {
628        #[snafu(implicit)]
629        location: Location,
630        #[snafu(source)]
631        error: rskafka::client::error::Error,
632    },
633
634    #[snafu(display(
635        "Failed to get a Kafka partition client, topic: {}, partition: {}",
636        topic,
637        partition
638    ))]
639    KafkaPartitionClient {
640        topic: String,
641        partition: i32,
642        #[snafu(implicit)]
643        location: Location,
644        #[snafu(source)]
645        error: rskafka::client::error::Error,
646    },
647
648    #[snafu(display(
649        "Failed to get offset from Kafka, topic: {}, partition: {}",
650        topic,
651        partition
652    ))]
653    KafkaGetOffset {
654        topic: String,
655        partition: i32,
656        #[snafu(implicit)]
657        location: Location,
658        #[snafu(source)]
659        error: rskafka::client::error::Error,
660    },
661
662    #[snafu(display("Failed to produce records to Kafka, topic: {}", topic))]
663    ProduceRecord {
664        topic: String,
665        #[snafu(implicit)]
666        location: Location,
667        #[snafu(source)]
668        error: rskafka::client::error::Error,
669    },
670
671    #[snafu(display("Failed to create a Kafka wal topic"))]
672    CreateKafkaWalTopic {
673        #[snafu(implicit)]
674        location: Location,
675        #[snafu(source)]
676        error: rskafka::client::error::Error,
677    },
678
679    #[snafu(display("The topic pool is empty"))]
680    EmptyTopicPool {
681        #[snafu(implicit)]
682        location: Location,
683    },
684
685    #[snafu(display("Unexpected table route type: {}", err_msg))]
686    UnexpectedLogicalRouteTable {
687        #[snafu(implicit)]
688        location: Location,
689        err_msg: String,
690    },
691
692    #[snafu(display("The tasks of {} cannot be empty", name))]
693    EmptyDdlTasks {
694        name: String,
695        #[snafu(implicit)]
696        location: Location,
697    },
698
699    #[snafu(display("Metadata corruption: {}", err_msg))]
700    MetadataCorruption {
701        err_msg: String,
702        #[snafu(implicit)]
703        location: Location,
704    },
705
706    #[snafu(display("Alter logical tables invalid arguments: {}", err_msg))]
707    AlterLogicalTablesInvalidArguments {
708        err_msg: String,
709        #[snafu(implicit)]
710        location: Location,
711    },
712
713    #[snafu(display("Create logical tables invalid arguments: {}", err_msg))]
714    CreateLogicalTablesInvalidArguments {
715        err_msg: String,
716        #[snafu(implicit)]
717        location: Location,
718    },
719
720    #[snafu(display("Invalid node info key: {}", key))]
721    InvalidNodeInfoKey {
722        key: String,
723        #[snafu(implicit)]
724        location: Location,
725    },
726
727    #[snafu(display("Invalid node stat key: {}", key))]
728    InvalidStatKey {
729        key: String,
730        #[snafu(implicit)]
731        location: Location,
732    },
733
734    #[snafu(display("Failed to parse number: {}", err_msg))]
735    ParseNum {
736        err_msg: String,
737        #[snafu(source)]
738        error: std::num::ParseIntError,
739        #[snafu(implicit)]
740        location: Location,
741    },
742
743    #[snafu(display("Invalid role: {}", role))]
744    InvalidRole {
745        role: i32,
746        #[snafu(implicit)]
747        location: Location,
748    },
749
750    #[snafu(display("Invalid set database option, key: {}, value: {}", key, value))]
751    InvalidSetDatabaseOption {
752        key: String,
753        value: String,
754        #[snafu(implicit)]
755        location: Location,
756    },
757
758    #[snafu(display("Invalid unset database option, key: {}", key))]
759    InvalidUnsetDatabaseOption {
760        key: String,
761        #[snafu(implicit)]
762        location: Location,
763    },
764
765    #[snafu(display("Invalid prefix: {}, key: {}", prefix, key))]
766    MismatchPrefix {
767        prefix: String,
768        key: String,
769        #[snafu(implicit)]
770        location: Location,
771    },
772
773    #[snafu(display("Failed to move values: {err_msg}"))]
774    MoveValues {
775        err_msg: String,
776        #[snafu(implicit)]
777        location: Location,
778    },
779
780    #[snafu(display("Failed to restore tombstone, target key already exists: {key}"))]
781    TombstoneTargetAlreadyExists {
782        key: String,
783        #[snafu(implicit)]
784        location: Location,
785    },
786
787    #[snafu(display("Failed to parse {} from utf8", name))]
788    FromUtf8 {
789        name: String,
790        #[snafu(source)]
791        error: std::string::FromUtf8Error,
792        #[snafu(implicit)]
793        location: Location,
794    },
795
796    #[snafu(display("Value not exists"))]
797    ValueNotExist {
798        #[snafu(implicit)]
799        location: Location,
800    },
801
802    #[snafu(display("Failed to get cache"))]
803    GetCache { source: Arc<Error> },
804
805    #[snafu(display(
806        "Failed to get latest cache value after {} attempts due to concurrent invalidation",
807        attempts
808    ))]
809    GetLatestCacheRetryExceeded {
810        attempts: usize,
811        #[snafu(implicit)]
812        location: Location,
813    },
814
815    #[cfg(feature = "pg_kvbackend")]
816    #[snafu(display("Failed to execute via Postgres, sql: {}", sql))]
817    PostgresExecution {
818        sql: String,
819        #[snafu(source)]
820        error: tokio_postgres::Error,
821        #[snafu(implicit)]
822        location: Location,
823    },
824
825    #[cfg(feature = "pg_kvbackend")]
826    #[snafu(display("Failed to create connection pool for Postgres"))]
827    CreatePostgresPool {
828        #[snafu(source)]
829        error: deadpool_postgres::CreatePoolError,
830        #[snafu(implicit)]
831        location: Location,
832    },
833
834    #[cfg(feature = "pg_kvbackend")]
835    #[snafu(display("Failed to get Postgres connection from pool: {}", reason))]
836    GetPostgresConnection {
837        reason: String,
838        #[snafu(implicit)]
839        location: Location,
840    },
841
842    #[cfg(feature = "pg_kvbackend")]
843    #[snafu(display("Failed to get Postgres client"))]
844    GetPostgresClient {
845        #[snafu(source)]
846        error: deadpool::managed::PoolError<tokio_postgres::Error>,
847        #[snafu(implicit)]
848        location: Location,
849    },
850
851    #[cfg(feature = "pg_kvbackend")]
852    #[snafu(display("Failed to {} Postgres transaction", operation))]
853    PostgresTransaction {
854        #[snafu(source)]
855        error: tokio_postgres::Error,
856        #[snafu(implicit)]
857        location: Location,
858        operation: String,
859    },
860
861    #[cfg(feature = "pg_kvbackend")]
862    #[snafu(display("Failed to setup PostgreSQL TLS configuration: {}", reason))]
863    PostgresTlsConfig {
864        reason: String,
865        #[snafu(implicit)]
866        location: Location,
867    },
868
869    #[snafu(display("Failed to load TLS certificate from path: {}", path))]
870    LoadTlsCertificate {
871        path: String,
872        #[snafu(source)]
873        error: std::io::Error,
874        #[snafu(implicit)]
875        location: Location,
876    },
877
878    #[cfg(feature = "pg_kvbackend")]
879    #[snafu(display("Invalid TLS configuration: {}", reason))]
880    InvalidTlsConfig {
881        reason: String,
882        #[snafu(implicit)]
883        location: Location,
884    },
885
886    #[cfg(feature = "mysql_kvbackend")]
887    #[snafu(display("Failed to execute via MySql, sql: {}", sql))]
888    MySqlExecution {
889        sql: String,
890        #[snafu(source)]
891        error: sqlx::Error,
892        #[snafu(implicit)]
893        location: Location,
894    },
895
896    #[cfg(feature = "mysql_kvbackend")]
897    #[snafu(display("Failed to create connection pool for MySql"))]
898    CreateMySqlPool {
899        #[snafu(source)]
900        error: sqlx::Error,
901        #[snafu(implicit)]
902        location: Location,
903    },
904
905    #[cfg(feature = "mysql_kvbackend")]
906    #[snafu(display("Failed to decode sql value"))]
907    DecodeSqlValue {
908        #[snafu(source)]
909        error: sqlx::error::Error,
910        #[snafu(implicit)]
911        location: Location,
912    },
913
914    #[cfg(feature = "mysql_kvbackend")]
915    #[snafu(display("Failed to acquire mysql client from pool"))]
916    AcquireMySqlClient {
917        #[snafu(source)]
918        error: sqlx::Error,
919        #[snafu(implicit)]
920        location: Location,
921    },
922
923    #[cfg(feature = "mysql_kvbackend")]
924    #[snafu(display("Failed to {} MySql transaction", operation))]
925    MySqlTransaction {
926        #[snafu(source)]
927        error: sqlx::Error,
928        #[snafu(implicit)]
929        location: Location,
930        operation: String,
931    },
932
933    #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
934    #[snafu(display("Rds transaction retry failed"))]
935    RdsTransactionRetryFailed {
936        #[snafu(implicit)]
937        location: Location,
938    },
939
940    #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
941    #[snafu(display("Sql execution timeout, sql: {}, duration: {:?}", sql, duration))]
942    SqlExecutionTimeout {
943        sql: String,
944        duration: std::time::Duration,
945        #[snafu(implicit)]
946        location: Location,
947    },
948
949    #[snafu(display(
950        "Datanode table info not found, table id: {}, datanode id: {}",
951        table_id,
952        datanode_id
953    ))]
954    DatanodeTableInfoNotFound {
955        datanode_id: DatanodeId,
956        table_id: TableId,
957        #[snafu(implicit)]
958        location: Location,
959    },
960
961    #[snafu(display("Invalid topic name prefix: {}", prefix))]
962    InvalidTopicNamePrefix {
963        prefix: String,
964        #[snafu(implicit)]
965        location: Location,
966    },
967
968    #[snafu(display("No leader found for table_id: {}", table_id))]
969    NoLeader {
970        table_id: TableId,
971        #[snafu(implicit)]
972        location: Location,
973    },
974
975    #[snafu(display(
976        "Procedure poison key already exists with a different value, key: {}, value: {}",
977        key,
978        value
979    ))]
980    ProcedurePoisonConflict {
981        key: String,
982        value: String,
983        #[snafu(implicit)]
984        location: Location,
985    },
986
987    #[snafu(display("Failed to put poison, table metadata may be corrupted"))]
988    PutPoison {
989        #[snafu(implicit)]
990        location: Location,
991        #[snafu(source)]
992        source: common_procedure::error::Error,
993    },
994
995    #[snafu(display("Invalid file path: {}", file_path))]
996    InvalidFilePath {
997        #[snafu(implicit)]
998        location: Location,
999        file_path: String,
1000    },
1001
1002    #[snafu(display("Failed to serialize flexbuffers"))]
1003    SerializeFlexbuffers {
1004        #[snafu(implicit)]
1005        location: Location,
1006        #[snafu(source)]
1007        error: flexbuffers::SerializationError,
1008    },
1009
1010    #[snafu(display("Failed to deserialize flexbuffers"))]
1011    DeserializeFlexbuffers {
1012        #[snafu(implicit)]
1013        location: Location,
1014        #[snafu(source)]
1015        error: flexbuffers::DeserializationError,
1016    },
1017
1018    #[snafu(display("Failed to read flexbuffers"))]
1019    ReadFlexbuffers {
1020        #[snafu(implicit)]
1021        location: Location,
1022        #[snafu(source)]
1023        error: flexbuffers::ReaderError,
1024    },
1025
1026    #[snafu(display("Invalid file name: {}", reason))]
1027    InvalidFileName {
1028        #[snafu(implicit)]
1029        location: Location,
1030        reason: String,
1031    },
1032
1033    #[snafu(display("Invalid file extension: {}", reason))]
1034    InvalidFileExtension {
1035        #[snafu(implicit)]
1036        location: Location,
1037        reason: String,
1038    },
1039
1040    #[snafu(display("Failed to write object, file path: {}", file_path))]
1041    WriteObject {
1042        #[snafu(implicit)]
1043        location: Location,
1044        file_path: String,
1045        #[snafu(source)]
1046        error: object_store::Error,
1047    },
1048
1049    #[snafu(display("Failed to read object, file path: {}", file_path))]
1050    ReadObject {
1051        #[snafu(implicit)]
1052        location: Location,
1053        file_path: String,
1054        #[snafu(source)]
1055        error: object_store::Error,
1056    },
1057
1058    #[snafu(display("Missing column ids"))]
1059    MissingColumnIds {
1060        #[snafu(implicit)]
1061        location: Location,
1062    },
1063
1064    #[snafu(display(
1065        "Missing column in column metadata: {}, table: {}, table_id: {}",
1066        column_name,
1067        table_name,
1068        table_id,
1069    ))]
1070    MissingColumnInColumnMetadata {
1071        column_name: String,
1072        #[snafu(implicit)]
1073        location: Location,
1074        table_name: String,
1075        table_id: TableId,
1076    },
1077
1078    #[snafu(display(
1079        "Mismatch column id: column_name: {}, column_id: {}, table: {}, table_id: {}",
1080        column_name,
1081        column_id,
1082        table_name,
1083        table_id,
1084    ))]
1085    MismatchColumnId {
1086        column_name: String,
1087        column_id: u32,
1088        #[snafu(implicit)]
1089        location: Location,
1090        table_name: String,
1091        table_id: TableId,
1092    },
1093
1094    #[snafu(display("Failed to convert column def, column: {}", column))]
1095    ConvertColumnDef {
1096        column: String,
1097        #[snafu(implicit)]
1098        location: Location,
1099        source: api::error::Error,
1100    },
1101
1102    #[snafu(display("Failed to convert time ranges"))]
1103    ConvertTimeRanges {
1104        #[snafu(implicit)]
1105        location: Location,
1106        source: api::error::Error,
1107    },
1108
1109    #[snafu(display(
1110        "Column metadata inconsistencies found in table: {}, table_id: {}",
1111        table_name,
1112        table_id
1113    ))]
1114    ColumnMetadataConflicts {
1115        table_name: String,
1116        table_id: TableId,
1117    },
1118
1119    #[snafu(display(
1120        "Column not found in column metadata, column_name: {}, column_id: {}",
1121        column_name,
1122        column_id
1123    ))]
1124    ColumnNotFound { column_name: String, column_id: u32 },
1125
1126    #[snafu(display(
1127        "Column id mismatch, column_name: {}, expected column_id: {}, actual column_id: {}",
1128        column_name,
1129        expected_column_id,
1130        actual_column_id
1131    ))]
1132    ColumnIdMismatch {
1133        column_name: String,
1134        expected_column_id: u32,
1135        actual_column_id: u32,
1136    },
1137
1138    #[snafu(display(
1139        "Timestamp column mismatch, expected column_name: {}, expected column_id: {}, actual column_name: {}, actual column_id: {}",
1140        expected_column_name,
1141        expected_column_id,
1142        actual_column_name,
1143        actual_column_id,
1144    ))]
1145    TimestampMismatch {
1146        expected_column_name: String,
1147        expected_column_id: u32,
1148        actual_column_name: String,
1149        actual_column_id: u32,
1150    },
1151
1152    #[cfg(feature = "enterprise")]
1153    #[snafu(display("Too large duration"))]
1154    TooLargeDuration {
1155        #[snafu(source)]
1156        error: prost_types::DurationError,
1157        #[snafu(implicit)]
1158        location: Location,
1159    },
1160
1161    #[cfg(feature = "enterprise")]
1162    #[snafu(display("Negative duration"))]
1163    NegativeDuration {
1164        #[snafu(source)]
1165        error: prost_types::DurationError,
1166        #[snafu(implicit)]
1167        location: Location,
1168    },
1169
1170    #[cfg(feature = "enterprise")]
1171    #[snafu(display("Missing interval field"))]
1172    MissingInterval {
1173        #[snafu(implicit)]
1174        location: Location,
1175    },
1176}
1177
1178pub type Result<T> = std::result::Result<T, Error>;
1179
1180impl ErrorExt for Error {
1181    fn status_code(&self) -> StatusCode {
1182        use Error::*;
1183        match self {
1184            IllegalServerState { .. }
1185            | EtcdTxnOpResponse { .. }
1186            | EtcdFailed { .. }
1187            | EtcdTxnFailed { .. }
1188            | ConnectEtcd { .. }
1189            | MoveValues { .. }
1190            | TombstoneTargetAlreadyExists { .. }
1191            | GetCache { .. }
1192            | GetLatestCacheRetryExceeded { .. }
1193            | SerializeToJson { .. }
1194            | DeserializeFromJson { .. }
1195            | ElectionNoLeader { .. }
1196            | ElectionLeaderLeaseExpired { .. }
1197            | ElectionLeaderLeaseChanged { .. } => StatusCode::Internal,
1198
1199            NoLeader { .. } => StatusCode::TableUnavailable,
1200            ValueNotExist { .. }
1201            | ProcedurePoisonConflict { .. }
1202            | ProcedureStateReceiverNotFound { .. }
1203            | MissingColumnIds { .. }
1204            | MissingColumnInColumnMetadata { .. }
1205            | MismatchColumnId { .. }
1206            | ColumnMetadataConflicts { .. }
1207            | ColumnNotFound { .. }
1208            | ColumnIdMismatch { .. }
1209            | TimestampMismatch { .. } => StatusCode::Unexpected,
1210
1211            Unsupported { .. } | ReadOnlyKvBackend { .. } => StatusCode::Unsupported,
1212            WriteObject { .. } | ReadObject { .. } => StatusCode::StorageUnavailable,
1213
1214            SerdeJson { .. }
1215            | ParseOption { .. }
1216            | InvalidProtoMsg { .. }
1217            | InvalidMetadata { .. }
1218            | Unexpected { .. }
1219            | TableInfoNotFound { .. }
1220            | NextSequence { .. }
1221            | UnexpectedSequenceValue { .. }
1222            | InvalidHeartbeatResponse { .. }
1223            | EncodeJson { .. }
1224            | DecodeJson { .. }
1225            | PayloadNotExist { .. }
1226            | ConvertRawKey { .. }
1227            | DecodeProto { .. }
1228            | DecodePackedFileRefs { .. }
1229            | InvalidPackedFileRefs { .. }
1230            | BuildTableMeta { .. }
1231            | TableRouteNotFound { .. }
1232            | TableRepartNotFound { .. }
1233            | RegionOperatingRace { .. }
1234            | SerializeWalOptions { .. }
1235            | BuildKafkaClient { .. }
1236            | BuildKafkaCtrlClient { .. }
1237            | KafkaPartitionClient { .. }
1238            | ProduceRecord { .. }
1239            | CreateKafkaWalTopic { .. }
1240            | EmptyTopicPool { .. }
1241            | UnexpectedLogicalRouteTable { .. }
1242            | ProcedureOutput { .. }
1243            | FromUtf8 { .. }
1244            | MetadataCorruption { .. }
1245            | KafkaGetOffset { .. }
1246            | ReadFlexbuffers { .. }
1247            | SerializeFlexbuffers { .. }
1248            | DeserializeFlexbuffers { .. }
1249            | ConvertTimeRanges { .. } => StatusCode::Unexpected,
1250
1251            GetKvCache { .. } | CacheNotGet { .. } => StatusCode::Internal,
1252
1253            SchemaAlreadyExists { .. } => StatusCode::DatabaseAlreadyExists,
1254
1255            ProcedureNotFound { .. }
1256            | InvalidViewInfo { .. }
1257            | InvalidFlowOption { .. }
1258            | PrimaryKeyNotFound { .. }
1259            | EmptyKey { .. }
1260            | AlterLogicalTablesInvalidArguments { .. }
1261            | CreateLogicalTablesInvalidArguments { .. }
1262            | MismatchPrefix { .. }
1263            | TlsConfig { .. }
1264            | InvalidSetDatabaseOption { .. }
1265            | InvalidUnsetDatabaseOption { .. }
1266            | InvalidTopicNamePrefix { .. }
1267            | InvalidFileExtension { .. }
1268            | InvalidFileName { .. }
1269            | InvalidFlowRequestBody { .. }
1270            | InvalidFilePath { .. }
1271            | ConflictingSchemaOptions { .. } => StatusCode::InvalidArguments,
1272
1273            #[cfg(feature = "enterprise")]
1274            MissingInterval { .. } | NegativeDuration { .. } | TooLargeDuration { .. } => {
1275                StatusCode::InvalidArguments
1276            }
1277
1278            FlowNotFound { .. } => StatusCode::FlowNotFound,
1279            FlowRouteNotFound { .. } => StatusCode::Unexpected,
1280            FlowAlreadyExists { .. } => StatusCode::FlowAlreadyExists,
1281
1282            ViewNotFound { .. } | TableNotFound { .. } | RegionNotFound { .. } => {
1283                StatusCode::TableNotFound
1284            }
1285            ViewAlreadyExists { .. }
1286            | TableAlreadyExists { .. }
1287            | TableNameTombstoneConflict { .. } => StatusCode::TableAlreadyExists,
1288
1289            SubmitProcedure { source, .. }
1290            | QueryProcedure { source, .. }
1291            | WaitProcedure { source, .. }
1292            | StartProcedureManager { source, .. }
1293            | StopProcedureManager { source, .. } => source.status_code(),
1294            RegisterProcedureLoader { source, .. } => source.status_code(),
1295            External { source, .. } => source.status_code(),
1296            ResponseExceededSizeLimit { source, .. } => source.status_code(),
1297            OperateDatanode { source, .. } => source.status_code(),
1298            Table { source, .. } => source.status_code(),
1299            RetryLater { source, .. } => source.status_code(),
1300            AbortProcedure { source, .. } => source.status_code(),
1301            ConvertAlterTableRequest { source, .. } => source.status_code(),
1302            PutPoison { source, .. } => source.status_code(),
1303            ConvertColumnDef { source, .. } => source.status_code(),
1304            ProcedureStateReceiver { source, .. } => source.status_code(),
1305            RegisterRepartitionProcedureLoader { source, .. } => source.status_code(),
1306            CreateRepartitionProcedure { source, .. } => source.status_code(),
1307            PersistRepartitionGcRequirement { source, .. } => source.status_code(),
1308
1309            ParseProcedureId { .. }
1310            | InvalidNumTopics { .. }
1311            | SchemaNotFound { .. }
1312            | CatalogNotFound { .. }
1313            | InvalidNodeInfoKey { .. }
1314            | InvalidStatKey { .. }
1315            | ParseNum { .. }
1316            | InvalidRole { .. }
1317            | EmptyDdlTasks { .. } => StatusCode::InvalidArguments,
1318
1319            LoadTlsCertificate { .. } => StatusCode::Internal,
1320
1321            #[cfg(feature = "pg_kvbackend")]
1322            PostgresExecution { .. }
1323            | CreatePostgresPool { .. }
1324            | GetPostgresConnection { .. }
1325            | GetPostgresClient { .. }
1326            | PostgresTransaction { .. }
1327            | PostgresTlsConfig { .. }
1328            | InvalidTlsConfig { .. } => StatusCode::Internal,
1329            #[cfg(feature = "mysql_kvbackend")]
1330            MySqlExecution { .. }
1331            | CreateMySqlPool { .. }
1332            | DecodeSqlValue { .. }
1333            | AcquireMySqlClient { .. }
1334            | MySqlTransaction { .. } => StatusCode::Internal,
1335            #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1336            RdsTransactionRetryFailed { .. } | SqlExecutionTimeout { .. } => StatusCode::Internal,
1337            DatanodeTableInfoNotFound { .. } => StatusCode::Internal,
1338        }
1339    }
1340
1341    fn as_any(&self) -> &dyn std::any::Any {
1342        self
1343    }
1344
1345    fn retry_hint(&self) -> RetryHint {
1346        use Error::*;
1347
1348        match self {
1349            RetryLater { .. }
1350            | GetLatestCacheRetryExceeded { .. }
1351            | NoLeader { .. }
1352            | ElectionNoLeader { .. }
1353            | ElectionLeaderLeaseExpired { .. }
1354            | ElectionLeaderLeaseChanged { .. } => RetryHint::Retryable,
1355            ConnectEtcd { error, .. } | EtcdFailed { error, .. } | EtcdTxnFailed { error, .. } => {
1356                retry_hint_from_etcd_error(error)
1357            }
1358            WriteObject { error, .. } | ReadObject { error, .. } => {
1359                retry_hint_from_opendal_error(error)
1360            }
1361            BuildKafkaClient { error, .. }
1362            | BuildKafkaCtrlClient { error, .. }
1363            | KafkaPartitionClient { error, .. }
1364            | KafkaGetOffset { error, .. }
1365            | ProduceRecord { error, .. }
1366            | CreateKafkaWalTopic { error, .. } => rskafka_client_error_to_retry_hint(error),
1367            SubmitProcedure { source, .. }
1368            | QueryProcedure { source, .. }
1369            | WaitProcedure { source, .. }
1370            | StartProcedureManager { source, .. }
1371            | StopProcedureManager { source, .. }
1372            | RegisterProcedureLoader { source, .. }
1373            | PutPoison { source, .. }
1374            | ProcedureStateReceiver { source, .. } => source.retry_hint(),
1375            External { source, .. }
1376            | ResponseExceededSizeLimit { source, .. }
1377            | OperateDatanode { source, .. }
1378            | AbortProcedure { source, .. }
1379            | RegisterRepartitionProcedureLoader { source, .. }
1380            | CreateRepartitionProcedure { source, .. }
1381            | PersistRepartitionGcRequirement { source, .. } => source.retry_hint(),
1382            Table { source, .. } => source.retry_hint(),
1383            ConvertAlterTableRequest { source, .. } => source.retry_hint(),
1384            ConvertColumnDef { source, .. } => source.retry_hint(),
1385            GetCache { source, .. } => source.retry_hint(),
1386            #[cfg(feature = "pg_kvbackend")]
1387            PostgresExecution { error, .. } | PostgresTransaction { error, .. } => {
1388                retry_hint_from_postgres_error(error)
1389            }
1390            #[cfg(feature = "pg_kvbackend")]
1391            GetPostgresClient { error, .. } => retry_hint_from_postgres_pool_error(error),
1392            #[cfg(feature = "mysql_kvbackend")]
1393            MySqlExecution { error, .. }
1394            | CreateMySqlPool { error, .. }
1395            | AcquireMySqlClient { error, .. }
1396            | MySqlTransaction { error, .. } => retry_hint_from_sqlx_error(error),
1397            #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1398            RdsTransactionRetryFailed { .. } | SqlExecutionTimeout { .. } => RetryHint::Retryable,
1399            _ => RetryHint::NonRetryable,
1400        }
1401    }
1402}
1403
1404impl Error {
1405    #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1406    /// Check if the error is a serialization error.
1407    pub fn is_serialization_error(&self) -> bool {
1408        match self {
1409            #[cfg(feature = "pg_kvbackend")]
1410            Error::PostgresExecution { error, .. } | Error::PostgresTransaction { error, .. } => {
1411                retry_hint::is_postgres_serialization_error(error)
1412            }
1413            #[cfg(feature = "mysql_kvbackend")]
1414            Error::MySqlExecution { error, .. } | Error::MySqlTransaction { error, .. } => {
1415                retry_hint::is_mysql_serialization_error(error)
1416            }
1417            _ => false,
1418        }
1419    }
1420
1421    /// Creates a new [Error::RetryLater] error from source `err`.
1422    pub fn retry_later<E: ErrorExt + Send + Sync + 'static>(err: E) -> Error {
1423        Error::RetryLater {
1424            source: BoxedError::new(err),
1425            clean_poisons: false,
1426        }
1427    }
1428
1429    /// Determine whether it is a retry later type through [StatusCode]
1430    pub fn is_retry_later(&self) -> bool {
1431        matches!(
1432            self,
1433            Error::RetryLater { .. } | Error::GetLatestCacheRetryExceeded { .. }
1434        )
1435    }
1436
1437    /// Determine whether it needs to clean poisons.
1438    pub fn need_clean_poisons(&self) -> bool {
1439        matches!(
1440            self,
1441            Error::AbortProcedure { clean_poisons, .. } if *clean_poisons
1442        ) || matches!(
1443            self,
1444            Error::RetryLater { clean_poisons, .. } if *clean_poisons
1445        )
1446    }
1447
1448    /// Returns true if the response exceeds the size limit.
1449    pub fn is_exceeded_size_limit(&self) -> bool {
1450        match self {
1451            Error::EtcdFailed {
1452                error: etcd_client::Error::GRpcStatus(status),
1453                ..
1454            } => status.code() == tonic::Code::OutOfRange,
1455            Error::ResponseExceededSizeLimit { .. } => true,
1456            _ => false,
1457        }
1458    }
1459}
1460
1461#[cfg(test)]
1462mod retry_hint_tests {
1463    use std::sync::Arc;
1464
1465    use common_error::mock::MockError;
1466
1467    use super::*;
1468
1469    #[test]
1470    fn test_retry_later_hint_is_retryable() {
1471        let err = Error::retry_later(MockError::new(StatusCode::Internal));
1472
1473        assert_eq!(err.retry_hint(), RetryHint::Retryable);
1474    }
1475
1476    #[test]
1477    fn test_latest_cache_retry_exceeded_hint_is_retryable() {
1478        let err = GetLatestCacheRetryExceededSnafu { attempts: 3_usize }.build();
1479
1480        assert_eq!(err.retry_hint(), RetryHint::Retryable);
1481    }
1482
1483    #[test]
1484    fn test_get_cache_forwards_retry_hint() {
1485        let source = Arc::new(Error::retry_later(MockError::new(StatusCode::Internal)));
1486        let err = Error::GetCache { source };
1487
1488        assert_eq!(err.retry_hint(), RetryHint::Retryable);
1489    }
1490
1491    #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1492    #[test]
1493    fn test_sql_execution_timeout_hint_is_retryable() {
1494        let err = SqlExecutionTimeoutSnafu {
1495            sql: "SELECT 1".to_string(),
1496            duration: std::time::Duration::from_secs(1),
1497        }
1498        .build();
1499
1500        assert_eq!(err.retry_hint(), RetryHint::Retryable);
1501    }
1502
1503    #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1504    #[test]
1505    fn test_rds_transaction_retry_failed_hint_is_retryable() {
1506        let err = RdsTransactionRetryFailedSnafu.build();
1507
1508        assert_eq!(err.retry_hint(), RetryHint::Retryable);
1509    }
1510
1511    #[test]
1512    fn test_default_hint_is_non_retryable() {
1513        let err = UnexpectedSnafu {
1514            err_msg: "mock error",
1515        }
1516        .build();
1517
1518        assert_eq!(err.retry_hint(), RetryHint::NonRetryable);
1519    }
1520}