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