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