Skip to main content

meta_srv/
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 common_error::define_into_tonic_status;
16use common_error::ext::{BoxedError, ErrorExt, RetryHint};
17use common_error::status_code::StatusCode;
18use common_macro::stack_trace_debug;
19use common_meta::DatanodeId;
20use common_procedure::ProcedureId;
21use common_runtime::JoinError;
22use common_wal::kafka::rskafka_client_error_to_retry_hint;
23use snafu::{Location, Snafu};
24use store_api::storage::RegionId;
25use table::metadata::TableId;
26use tokio::sync::mpsc::error::SendError;
27use tonic::codegen::http;
28use uuid::Uuid;
29
30use crate::metasrv::SelectTarget;
31use crate::pubsub::Message;
32use crate::service::mailbox::Channel;
33
34#[derive(Snafu)]
35#[snafu(visibility(pub))]
36#[stack_trace_debug]
37pub enum Error {
38    #[snafu(display("Failed to choose items"))]
39    ChooseItems {
40        #[snafu(implicit)]
41        location: Location,
42        #[snafu(source)]
43        error: rand::distr::weighted::Error,
44    },
45
46    #[snafu(display("Exceeded deadline, operation: {}", operation))]
47    ExceededDeadline {
48        #[snafu(implicit)]
49        location: Location,
50        operation: String,
51    },
52
53    #[snafu(display("The target peer is unavailable temporally: {}", peer_id))]
54    PeerUnavailable {
55        #[snafu(implicit)]
56        location: Location,
57        peer_id: u64,
58    },
59
60    #[snafu(display("Failed to list active frontends"))]
61    ListActiveFrontends {
62        #[snafu(implicit)]
63        location: Location,
64        source: common_meta::error::Error,
65    },
66
67    #[snafu(display("Failed to list active datanodes"))]
68    ListActiveDatanodes {
69        #[snafu(implicit)]
70        location: Location,
71        source: common_meta::error::Error,
72    },
73
74    #[snafu(display("Failed to list active flownodes"))]
75    ListActiveFlownodes {
76        #[snafu(implicit)]
77        location: Location,
78        source: common_meta::error::Error,
79    },
80
81    #[snafu(display("No available frontend"))]
82    NoAvailableFrontend {
83        #[snafu(implicit)]
84        location: Location,
85    },
86
87    #[snafu(display("Another migration procedure is running for region: {}", region_id))]
88    MigrationRunning {
89        #[snafu(implicit)]
90        location: Location,
91        region_id: RegionId,
92    },
93
94    #[snafu(display("Another drain procedure is running for datanode: {}", node_id))]
95    DrainDatanodeRunning {
96        #[snafu(implicit)]
97        location: Location,
98        node_id: DatanodeId,
99    },
100
101    #[snafu(display(
102        "The region migration procedure is completed for region: {}, target_peer: {}",
103        region_id,
104        target_peer_id
105    ))]
106    RegionMigrated {
107        #[snafu(implicit)]
108        location: Location,
109        region_id: RegionId,
110        target_peer_id: u64,
111    },
112
113    #[snafu(display("The region migration procedure aborted, reason: {}", reason))]
114    MigrationAbort {
115        #[snafu(implicit)]
116        location: Location,
117        reason: String,
118    },
119
120    #[snafu(display(
121        "Another procedure is operating the region: {} on peer: {}",
122        region_id,
123        peer_id
124    ))]
125    RegionOperatingRace {
126        #[snafu(implicit)]
127        location: Location,
128        peer_id: DatanodeId,
129        region_id: RegionId,
130    },
131
132    #[snafu(display("Failed to init ddl manager"))]
133    InitDdlManager {
134        #[snafu(implicit)]
135        location: Location,
136        source: common_meta::error::Error,
137    },
138
139    #[snafu(display("Failed to init reconciliation manager"))]
140    InitReconciliationManager {
141        #[snafu(implicit)]
142        location: Location,
143        source: common_meta::error::Error,
144    },
145
146    #[snafu(display("Failed to create default catalog and schema"))]
147    InitMetadata {
148        #[snafu(implicit)]
149        location: Location,
150        source: common_meta::error::Error,
151    },
152
153    #[snafu(display("Failed to allocate next sequence number"))]
154    NextSequence {
155        #[snafu(implicit)]
156        location: Location,
157        source: common_meta::error::Error,
158    },
159
160    #[snafu(display("Failed to set next sequence number"))]
161    SetNextSequence {
162        #[snafu(implicit)]
163        location: Location,
164        source: common_meta::error::Error,
165    },
166
167    #[snafu(display("Failed to peek sequence number"))]
168    PeekSequence {
169        #[snafu(implicit)]
170        location: Location,
171        source: common_meta::error::Error,
172    },
173
174    #[snafu(display("Failed to start telemetry task"))]
175    StartTelemetryTask {
176        #[snafu(implicit)]
177        location: Location,
178        source: common_runtime::error::Error,
179    },
180
181    #[snafu(display("Failed to submit ddl task"))]
182    SubmitDdlTask {
183        #[snafu(implicit)]
184        location: Location,
185        source: common_meta::error::Error,
186    },
187
188    #[snafu(display("Failed to submit reconcile procedure"))]
189    SubmitReconcileProcedure {
190        #[snafu(implicit)]
191        location: Location,
192        source: common_meta::error::Error,
193    },
194
195    #[snafu(display("Failed to invalidate table cache"))]
196    InvalidateTableCache {
197        #[snafu(implicit)]
198        location: Location,
199        source: common_meta::error::Error,
200    },
201
202    #[snafu(display("Failed to list catalogs"))]
203    ListCatalogs {
204        #[snafu(implicit)]
205        location: Location,
206        source: BoxedError,
207    },
208
209    #[snafu(display("Failed to list {}'s schemas", catalog))]
210    ListSchemas {
211        #[snafu(implicit)]
212        location: Location,
213        catalog: String,
214        source: BoxedError,
215    },
216
217    #[snafu(display("Failed to list {}.{}'s tables", catalog, schema))]
218    ListTables {
219        #[snafu(implicit)]
220        location: Location,
221        catalog: String,
222        schema: String,
223        source: BoxedError,
224    },
225
226    #[snafu(display("Failed to join a future"))]
227    Join {
228        #[snafu(implicit)]
229        location: Location,
230        #[snafu(source)]
231        error: JoinError,
232    },
233
234    #[snafu(display(
235        "Failed to request {}, required: {}, but only {} available",
236        select_target,
237        required,
238        available
239    ))]
240    NoEnoughAvailableNode {
241        #[snafu(implicit)]
242        location: Location,
243        required: usize,
244        available: usize,
245        select_target: SelectTarget,
246    },
247
248    #[snafu(display("Failed to send shutdown signal"))]
249    SendShutdownSignal {
250        #[snafu(source)]
251        error: SendError<()>,
252    },
253
254    #[snafu(display("Failed to shutdown {} server", server))]
255    ShutdownServer {
256        #[snafu(implicit)]
257        location: Location,
258        source: servers::error::Error,
259        server: String,
260    },
261
262    #[snafu(display("Empty key is not allowed"))]
263    EmptyKey {
264        #[snafu(implicit)]
265        location: Location,
266    },
267
268    #[snafu(display("Failed to execute via Etcd"))]
269    EtcdFailed {
270        #[snafu(source)]
271        error: etcd_client::Error,
272        #[snafu(implicit)]
273        location: Location,
274    },
275
276    #[snafu(display("Failed to connect to Etcd"))]
277    ConnectEtcd {
278        #[snafu(source)]
279        error: etcd_client::Error,
280        #[snafu(implicit)]
281        location: Location,
282    },
283
284    #[snafu(display("Failed to read file: {}", path))]
285    FileIo {
286        #[snafu(source)]
287        error: std::io::Error,
288        #[snafu(implicit)]
289        location: Location,
290        path: String,
291    },
292
293    #[snafu(display("Failed to bind address {}", addr))]
294    TcpBind {
295        addr: String,
296        #[snafu(source)]
297        error: std::io::Error,
298        #[snafu(implicit)]
299        location: Location,
300    },
301
302    #[snafu(display("Failed to start gRPC server"))]
303    StartGrpc {
304        #[snafu(source)]
305        error: tonic::transport::Error,
306        #[snafu(implicit)]
307        location: Location,
308    },
309
310    #[snafu(display("Failed to start http server"))]
311    StartHttp {
312        #[snafu(implicit)]
313        location: Location,
314        source: servers::error::Error,
315    },
316
317    #[snafu(display("Failed to parse address {}", addr))]
318    ParseAddr {
319        addr: String,
320        #[snafu(source)]
321        error: std::net::AddrParseError,
322    },
323
324    #[snafu(display("Invalid lease key: {}", key))]
325    InvalidLeaseKey {
326        key: String,
327        #[snafu(implicit)]
328        location: Location,
329    },
330
331    #[snafu(display("Invalid datanode stat key: {}", key))]
332    InvalidStatKey {
333        key: String,
334        #[snafu(implicit)]
335        location: Location,
336    },
337
338    #[snafu(display("Invalid inactive region key: {}", key))]
339    InvalidInactiveRegionKey {
340        key: String,
341        #[snafu(implicit)]
342        location: Location,
343    },
344
345    #[snafu(display("Invalid node scheduling key: {}", key))]
346    InvalidNodeSchedulingKey {
347        #[snafu(implicit)]
348        location: Location,
349        key: String,
350    },
351
352    #[snafu(display("Failed to parse lease key from utf8"))]
353    LeaseKeyFromUtf8 {
354        #[snafu(source)]
355        error: std::string::FromUtf8Error,
356        #[snafu(implicit)]
357        location: Location,
358    },
359
360    #[snafu(display("Failed to parse lease value from utf8"))]
361    LeaseValueFromUtf8 {
362        #[snafu(source)]
363        error: std::string::FromUtf8Error,
364        #[snafu(implicit)]
365        location: Location,
366    },
367
368    #[snafu(display("Failed to parse invalid region key from utf8"))]
369    InvalidRegionKeyFromUtf8 {
370        #[snafu(source)]
371        error: std::string::FromUtf8Error,
372        #[snafu(implicit)]
373        location: Location,
374    },
375
376    #[snafu(display("Failed to serialize to json: {}", input))]
377    SerializeToJson {
378        input: String,
379        #[snafu(source)]
380        error: serde_json::error::Error,
381        #[snafu(implicit)]
382        location: Location,
383    },
384
385    #[snafu(display("Failed to deserialize from json payload of length {}", input_len))]
386    DeserializeFromJson {
387        input_len: usize,
388        #[snafu(source)]
389        error: serde_json::error::Error,
390        #[snafu(implicit)]
391        location: Location,
392    },
393
394    #[snafu(display("Failed to serialize config"))]
395    SerializeConfig {
396        #[snafu(source)]
397        error: serde_json::error::Error,
398        #[snafu(implicit)]
399        location: Location,
400    },
401
402    #[snafu(display("Failed to parse number: {}", err_msg))]
403    ParseNum {
404        err_msg: String,
405        #[snafu(source)]
406        error: std::num::ParseIntError,
407        #[snafu(implicit)]
408        location: Location,
409    },
410
411    #[snafu(display("Failed to parse bool: {}", err_msg))]
412    ParseBool {
413        err_msg: String,
414        #[snafu(source)]
415        error: std::str::ParseBoolError,
416        #[snafu(implicit)]
417        location: Location,
418    },
419
420    #[snafu(display("Failed to downgrade region leader, region: {}", region_id))]
421    DowngradeLeader {
422        region_id: RegionId,
423        #[snafu(implicit)]
424        location: Location,
425        #[snafu(source)]
426        source: BoxedError,
427    },
428
429    #[snafu(display("Region's leader peer changed: {}", msg))]
430    LeaderPeerChanged {
431        msg: String,
432        #[snafu(implicit)]
433        location: Location,
434    },
435
436    #[snafu(display("Invalid arguments: {}", err_msg))]
437    InvalidArguments {
438        err_msg: String,
439        #[snafu(implicit)]
440        location: Location,
441    },
442
443    #[snafu(display("Manual GC is rejected because maintenance mode is enabled"))]
444    ManualGcRejectedByMaintenanceMode {
445        #[snafu(implicit)]
446        location: Location,
447    },
448
449    #[cfg(feature = "mysql_kvbackend")]
450    #[snafu(display("Failed to parse mysql url: {}", mysql_url))]
451    ParseMySqlUrl {
452        #[snafu(source)]
453        error: sqlx::error::Error,
454        mysql_url: String,
455        #[snafu(implicit)]
456        location: Location,
457    },
458
459    #[cfg(feature = "mysql_kvbackend")]
460    #[snafu(display("Failed to decode sql value"))]
461    DecodeSqlValue {
462        #[snafu(source)]
463        error: sqlx::error::Error,
464        #[snafu(implicit)]
465        location: Location,
466    },
467
468    #[snafu(display("Failed to find table route for {table_id}"))]
469    TableRouteNotFound {
470        table_id: TableId,
471        #[snafu(implicit)]
472        location: Location,
473    },
474
475    #[snafu(display("Failed to find table route for {region_id}"))]
476    RegionRouteNotFound {
477        region_id: RegionId,
478        #[snafu(implicit)]
479        location: Location,
480    },
481
482    #[snafu(display("Table info not found: {}", table_id))]
483    TableInfoNotFound {
484        table_id: TableId,
485        #[snafu(implicit)]
486        location: Location,
487    },
488
489    #[snafu(display("Datanode table not found: {}, datanode: {}", table_id, datanode_id))]
490    DatanodeTableNotFound {
491        table_id: TableId,
492        datanode_id: DatanodeId,
493        #[snafu(implicit)]
494        location: Location,
495    },
496
497    #[snafu(display("Metasrv has no leader at this moment"))]
498    NoLeader {
499        #[snafu(implicit)]
500        location: Location,
501    },
502
503    #[snafu(display("Leader lease expired"))]
504    LeaderLeaseExpired {
505        #[snafu(implicit)]
506        location: Location,
507    },
508
509    #[snafu(display("Leader lease changed during election"))]
510    LeaderLeaseChanged {
511        #[snafu(implicit)]
512        location: Location,
513    },
514
515    #[snafu(display("Table {} not found", name))]
516    TableNotFound {
517        name: String,
518        #[snafu(implicit)]
519        location: Location,
520    },
521
522    #[snafu(display("Unsupported selector type, {}", selector_type))]
523    UnsupportedSelectorType {
524        selector_type: String,
525        #[snafu(implicit)]
526        location: Location,
527    },
528
529    #[snafu(display("Unexpected, violated: {violated}"))]
530    Unexpected {
531        violated: String,
532        #[snafu(implicit)]
533        location: Location,
534    },
535
536    #[snafu(display("Failed to create gRPC channel"))]
537    CreateChannel {
538        #[snafu(implicit)]
539        location: Location,
540        source: common_grpc::error::Error,
541    },
542
543    #[snafu(display("Failed to batch get KVs from leader's in_memory kv store"))]
544    BatchGet {
545        #[snafu(source)]
546        error: tonic::Status,
547        #[snafu(implicit)]
548        location: Location,
549    },
550
551    #[snafu(display("Failed to batch range KVs from leader's in_memory kv store"))]
552    Range {
553        #[snafu(source)]
554        error: tonic::Status,
555        #[snafu(implicit)]
556        location: Location,
557    },
558
559    #[snafu(display("Response header not found"))]
560    ResponseHeaderNotFound {
561        #[snafu(implicit)]
562        location: Location,
563    },
564
565    #[snafu(display("The requested meta node is not leader, node addr: {}", node_addr))]
566    IsNotLeader {
567        node_addr: String,
568        #[snafu(implicit)]
569        location: Location,
570    },
571
572    #[snafu(display("Invalid http body"))]
573    InvalidHttpBody {
574        #[snafu(source)]
575        error: http::Error,
576        #[snafu(implicit)]
577        location: Location,
578    },
579
580    #[snafu(display(
581        "The number of retries for the grpc call {} exceeded the limit, {}",
582        func_name,
583        retry_num
584    ))]
585    ExceededRetryLimit {
586        func_name: String,
587        retry_num: usize,
588        #[snafu(implicit)]
589        location: Location,
590    },
591
592    #[snafu(display("Invalid utf-8 value"))]
593    InvalidUtf8Value {
594        #[snafu(source)]
595        error: std::string::FromUtf8Error,
596        #[snafu(implicit)]
597        location: Location,
598    },
599
600    #[snafu(display("Missing required parameter, param: {:?}", param))]
601    MissingRequiredParameter { param: String },
602
603    #[snafu(display("Failed to start procedure manager"))]
604    StartProcedureManager {
605        #[snafu(implicit)]
606        location: Location,
607        source: common_procedure::Error,
608    },
609
610    #[snafu(display("Failed to stop procedure manager"))]
611    StopProcedureManager {
612        #[snafu(implicit)]
613        location: Location,
614        source: common_procedure::Error,
615    },
616
617    #[snafu(display("Failed to wait procedure done"))]
618    WaitProcedure {
619        #[snafu(implicit)]
620        location: Location,
621        source: common_procedure::Error,
622    },
623
624    #[snafu(display("Failed to query procedure state"))]
625    QueryProcedure {
626        #[snafu(implicit)]
627        location: Location,
628        source: common_procedure::Error,
629    },
630
631    #[snafu(display("Procedure not found: {pid}"))]
632    ProcedureNotFound {
633        #[snafu(implicit)]
634        location: Location,
635        pid: String,
636    },
637
638    #[snafu(display("Failed to submit procedure"))]
639    SubmitProcedure {
640        #[snafu(implicit)]
641        location: Location,
642        source: common_procedure::Error,
643    },
644
645    #[snafu(display("A prune task for topic {} is already running", topic))]
646    PruneTaskAlreadyRunning {
647        topic: String,
648        #[snafu(implicit)]
649        location: Location,
650    },
651
652    #[snafu(display("Schema already exists, name: {schema_name}"))]
653    SchemaAlreadyExists {
654        schema_name: String,
655        #[snafu(implicit)]
656        location: Location,
657    },
658
659    #[snafu(display("Table already exists: {table_name}"))]
660    TableAlreadyExists {
661        table_name: String,
662        #[snafu(implicit)]
663        location: Location,
664    },
665
666    #[snafu(display("Pusher not found: {pusher_id}"))]
667    PusherNotFound {
668        pusher_id: String,
669        #[snafu(implicit)]
670        location: Location,
671    },
672
673    #[snafu(display("Failed to push message: {err_msg}"))]
674    PushMessage {
675        err_msg: String,
676        #[snafu(implicit)]
677        location: Location,
678    },
679
680    #[snafu(display("Mailbox already closed: {id}"))]
681    MailboxClosed {
682        id: u64,
683        #[snafu(implicit)]
684        location: Location,
685    },
686
687    #[snafu(display("Mailbox timeout: {id}"))]
688    MailboxTimeout {
689        id: u64,
690        #[snafu(implicit)]
691        location: Location,
692    },
693
694    #[snafu(display("Mailbox receiver got an error: {id}, {err_msg}"))]
695    MailboxReceiver {
696        id: u64,
697        err_msg: String,
698        #[snafu(implicit)]
699        location: Location,
700    },
701
702    #[snafu(display("Mailbox channel closed: {channel}"))]
703    MailboxChannelClosed {
704        channel: Channel,
705        #[snafu(implicit)]
706        location: Location,
707    },
708
709    #[snafu(display("Missing request header"))]
710    MissingRequestHeader {
711        #[snafu(implicit)]
712        location: Location,
713    },
714
715    #[snafu(display("Failed to register procedure loader, type name: {}", type_name))]
716    RegisterProcedureLoader {
717        type_name: String,
718        #[snafu(implicit)]
719        location: Location,
720        source: common_procedure::error::Error,
721    },
722
723    #[snafu(display(
724        "Received unexpected instruction reply, mailbox message: {}, reason: {}",
725        mailbox_message,
726        reason
727    ))]
728    UnexpectedInstructionReply {
729        mailbox_message: String,
730        reason: String,
731        #[snafu(implicit)]
732        location: Location,
733    },
734
735    #[snafu(display("Expected to retry later, reason: {}", reason))]
736    RetryLater {
737        reason: String,
738        #[snafu(implicit)]
739        location: Location,
740    },
741
742    #[snafu(display("Expected to retry later, reason: {}", reason))]
743    RetryLaterWithSource {
744        reason: String,
745        #[snafu(implicit)]
746        location: Location,
747        source: BoxedError,
748    },
749
750    #[snafu(display("Failed to convert proto data"))]
751    ConvertProtoData {
752        #[snafu(implicit)]
753        location: Location,
754        source: common_meta::error::Error,
755    },
756
757    // this error is used for custom error mapping
758    // please do not delete it
759    #[snafu(display("Other error"))]
760    Other {
761        source: BoxedError,
762        #[snafu(implicit)]
763        location: Location,
764    },
765
766    #[snafu(display("Table metadata manager error"))]
767    TableMetadataManager {
768        source: common_meta::error::Error,
769        #[snafu(implicit)]
770        location: Location,
771    },
772
773    #[snafu(display("Runtime switch manager error"))]
774    RuntimeSwitchManager {
775        source: common_meta::error::Error,
776        #[snafu(implicit)]
777        location: Location,
778    },
779
780    #[snafu(display("Keyvalue backend error"))]
781    KvBackend {
782        source: common_meta::error::Error,
783        #[snafu(implicit)]
784        location: Location,
785    },
786
787    #[snafu(display("Failed to publish message"))]
788    PublishMessage {
789        #[snafu(source)]
790        error: SendError<Message>,
791        #[snafu(implicit)]
792        location: Location,
793    },
794
795    #[snafu(display("Too many partitions"))]
796    TooManyPartitions {
797        #[snafu(implicit)]
798        location: Location,
799    },
800
801    #[snafu(display("Failed to create repartition subtasks"))]
802    RepartitionCreateSubtasks {
803        source: partition::error::Error,
804        #[snafu(implicit)]
805        location: Location,
806    },
807
808    #[snafu(display("Failed to manage the repartition GC requirement"))]
809    RepartitionGcRequirement {
810        source: common_meta::error::Error,
811        #[snafu(implicit)]
812        location: Location,
813    },
814
815    #[snafu(display("Failed to inspect persisted repartition procedures"))]
816    InspectRepartitionProcedures {
817        source: common_procedure::Error,
818        #[snafu(implicit)]
819        location: Location,
820    },
821
822    #[snafu(display(
823        "Metasrv GC must be enabled because the cluster has durable repartition state"
824    ))]
825    RepartitionGcRequired {
826        #[snafu(implicit)]
827        location: Location,
828    },
829
830    #[snafu(display(
831        "Source partition expression '{}' does not match any existing region",
832        expr
833    ))]
834    RepartitionSourceExprMismatch {
835        expr: String,
836        #[snafu(implicit)]
837        location: Location,
838    },
839
840    #[snafu(display(
841        "Failed to get the state receiver for repartition subprocedure {}",
842        procedure_id
843    ))]
844    RepartitionSubprocedureStateReceiver {
845        procedure_id: ProcedureId,
846        #[snafu(source)]
847        source: common_procedure::Error,
848        #[snafu(implicit)]
849        location: Location,
850    },
851
852    #[snafu(display("Unsupported operation {}", operation))]
853    Unsupported {
854        operation: String,
855        #[snafu(implicit)]
856        location: Location,
857    },
858
859    #[snafu(display("Unexpected table route type: {}", err_msg))]
860    UnexpectedLogicalRouteTable {
861        #[snafu(implicit)]
862        location: Location,
863        err_msg: String,
864        source: common_meta::error::Error,
865    },
866
867    #[snafu(display("Failed to save cluster info"))]
868    SaveClusterInfo {
869        #[snafu(implicit)]
870        location: Location,
871        source: common_meta::error::Error,
872    },
873
874    #[snafu(display("Invalid cluster info format"))]
875    InvalidClusterInfoFormat {
876        #[snafu(implicit)]
877        location: Location,
878        source: common_meta::error::Error,
879    },
880
881    #[snafu(display("Invalid datanode stat format"))]
882    InvalidDatanodeStatFormat {
883        #[snafu(implicit)]
884        location: Location,
885        source: common_meta::error::Error,
886    },
887
888    #[snafu(display("Invalid node info format"))]
889    InvalidNodeInfoFormat {
890        #[snafu(implicit)]
891        location: Location,
892        source: common_meta::error::Error,
893    },
894
895    #[snafu(display("Failed to serialize options to TOML"))]
896    TomlFormat {
897        #[snafu(implicit)]
898        location: Location,
899        #[snafu(source(from(common_config::error::Error, Box::new)))]
900        source: Box<common_config::error::Error>,
901    },
902
903    #[cfg(feature = "pg_kvbackend")]
904    #[snafu(display("Failed to execute via postgres, sql: {}", sql))]
905    PostgresExecution {
906        #[snafu(source)]
907        error: tokio_postgres::Error,
908        sql: String,
909        #[snafu(implicit)]
910        location: Location,
911    },
912
913    #[cfg(feature = "pg_kvbackend")]
914    #[snafu(display("Failed to get Postgres client"))]
915    GetPostgresClient {
916        #[snafu(implicit)]
917        location: Location,
918        #[snafu(source)]
919        error: deadpool::managed::PoolError<tokio_postgres::Error>,
920    },
921
922    #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
923    #[snafu(display("Sql execution timeout, sql: {}, duration: {:?}", sql, duration))]
924    SqlExecutionTimeout {
925        #[snafu(implicit)]
926        location: Location,
927        sql: String,
928        duration: std::time::Duration,
929    },
930
931    #[cfg(feature = "pg_kvbackend")]
932    #[snafu(display("Failed to create connection pool for Postgres"))]
933    CreatePostgresPool {
934        #[snafu(source)]
935        error: deadpool_postgres::CreatePoolError,
936        #[snafu(implicit)]
937        location: Location,
938    },
939
940    #[cfg(feature = "pg_kvbackend")]
941    #[snafu(display("Failed to get connection from Postgres pool: {}", reason))]
942    GetPostgresConnection {
943        reason: String,
944        #[snafu(implicit)]
945        location: Location,
946    },
947
948    #[cfg(feature = "mysql_kvbackend")]
949    #[snafu(display("Failed to execute via mysql, sql: {}", sql))]
950    MySqlExecution {
951        #[snafu(source)]
952        error: sqlx::Error,
953        #[snafu(implicit)]
954        location: Location,
955        sql: String,
956    },
957
958    #[cfg(feature = "mysql_kvbackend")]
959    #[snafu(display("Failed to create mysql pool"))]
960    CreateMySqlPool {
961        #[snafu(source)]
962        error: sqlx::Error,
963        #[snafu(implicit)]
964        location: Location,
965    },
966
967    #[cfg(feature = "mysql_kvbackend")]
968    #[snafu(display("Failed to acquire mysql client from pool"))]
969    AcquireMySqlClient {
970        #[snafu(source)]
971        error: sqlx::Error,
972        #[snafu(implicit)]
973        location: Location,
974    },
975
976    #[snafu(display("Handler not found: {}", name))]
977    HandlerNotFound {
978        name: String,
979        #[snafu(implicit)]
980        location: Location,
981    },
982
983    #[snafu(display("Flow state handler error"))]
984    FlowStateHandler {
985        #[snafu(implicit)]
986        location: Location,
987        source: common_meta::error::Error,
988    },
989
990    #[snafu(display("Failed to build wal provider"))]
991    BuildWalProvider {
992        #[snafu(implicit)]
993        location: Location,
994        source: common_meta::error::Error,
995    },
996
997    #[snafu(display("Failed to build kafka client."))]
998    BuildKafkaClient {
999        #[snafu(implicit)]
1000        location: Location,
1001        #[snafu(source)]
1002        error: common_meta::error::Error,
1003    },
1004
1005    #[snafu(display(
1006        "Failed to build a Kafka partition client, topic: {}, partition: {}",
1007        topic,
1008        partition
1009    ))]
1010    BuildPartitionClient {
1011        topic: String,
1012        partition: i32,
1013        #[snafu(implicit)]
1014        location: Location,
1015        #[snafu(source)]
1016        error: rskafka::client::error::Error,
1017    },
1018
1019    #[snafu(display(
1020        "Failed to delete records from Kafka, topic: {}, partition: {}, offset: {}",
1021        topic,
1022        partition,
1023        offset
1024    ))]
1025    DeleteRecords {
1026        #[snafu(implicit)]
1027        location: Location,
1028        #[snafu(source)]
1029        error: rskafka::client::error::Error,
1030        topic: String,
1031        partition: i32,
1032        offset: u64,
1033    },
1034
1035    #[snafu(display("Failed to get offset from Kafka, topic: {}", topic))]
1036    GetOffset {
1037        topic: String,
1038        #[snafu(implicit)]
1039        location: Location,
1040        #[snafu(source)]
1041        error: rskafka::client::error::Error,
1042    },
1043
1044    #[snafu(display("Failed to update the TopicNameValue in kvbackend, topic: {}", topic))]
1045    UpdateTopicNameValue {
1046        topic: String,
1047        #[snafu(implicit)]
1048        location: Location,
1049        #[snafu(source)]
1050        source: common_meta::error::Error,
1051    },
1052
1053    #[snafu(display("Failed to build tls options"))]
1054    BuildTlsOptions {
1055        #[snafu(implicit)]
1056        location: Location,
1057        #[snafu(source)]
1058        source: common_meta::error::Error,
1059    },
1060
1061    #[snafu(display(
1062        "Repartition group {} source region missing, region id: {}",
1063        group_id,
1064        region_id
1065    ))]
1066    RepartitionSourceRegionMissing {
1067        group_id: Uuid,
1068        region_id: RegionId,
1069        #[snafu(implicit)]
1070        location: Location,
1071    },
1072
1073    #[snafu(display(
1074        "Repartition group {} target region missing, region id: {}",
1075        group_id,
1076        region_id
1077    ))]
1078    RepartitionTargetRegionMissing {
1079        group_id: Uuid,
1080        region_id: RegionId,
1081        #[snafu(implicit)]
1082        location: Location,
1083    },
1084
1085    #[snafu(display("Failed to serialize partition expression"))]
1086    SerializePartitionExpr {
1087        #[snafu(source)]
1088        source: partition::error::Error,
1089        #[snafu(implicit)]
1090        location: Location,
1091    },
1092
1093    #[snafu(display("Failed to deserialize partition expression"))]
1094    DeserializePartitionExpr {
1095        #[snafu(source)]
1096        source: partition::error::Error,
1097        #[snafu(implicit)]
1098        location: Location,
1099    },
1100
1101    #[snafu(display("Empty partition expression"))]
1102    EmptyPartitionExpr {
1103        #[snafu(implicit)]
1104        location: Location,
1105    },
1106
1107    #[snafu(display(
1108        "Partition expression mismatch, region id: {}, expected: {}, actual: {}",
1109        region_id,
1110        expected,
1111        actual
1112    ))]
1113    PartitionExprMismatch {
1114        region_id: RegionId,
1115        expected: String,
1116        actual: String,
1117        #[snafu(implicit)]
1118        location: Location,
1119    },
1120
1121    #[snafu(display("Failed to allocate regions for table: {}", table_id))]
1122    AllocateRegions {
1123        #[snafu(implicit)]
1124        location: Location,
1125        table_id: TableId,
1126        #[snafu(source)]
1127        source: common_meta::error::Error,
1128    },
1129
1130    #[snafu(display("Failed to deallocate regions for table: {}", table_id))]
1131    DeallocateRegions {
1132        #[snafu(implicit)]
1133        location: Location,
1134        table_id: TableId,
1135        #[snafu(source)]
1136        source: common_meta::error::Error,
1137    },
1138
1139    #[snafu(display("Failed to build create request for table: {}", table_id))]
1140    BuildCreateRequest {
1141        #[snafu(implicit)]
1142        location: Location,
1143        table_id: TableId,
1144        #[snafu(source)]
1145        source: common_meta::error::Error,
1146    },
1147
1148    #[snafu(display("Failed to allocate region routes for table: {}", table_id))]
1149    AllocateRegionRoutes {
1150        #[snafu(implicit)]
1151        location: Location,
1152        table_id: TableId,
1153        #[snafu(source)]
1154        source: common_meta::error::Error,
1155    },
1156
1157    #[snafu(display("Failed to allocate wal options for table: {}", table_id))]
1158    AllocateWalOptions {
1159        #[snafu(implicit)]
1160        location: Location,
1161        table_id: TableId,
1162        #[snafu(source)]
1163        source: common_meta::error::Error,
1164    },
1165}
1166
1167impl Error {
1168    /// Returns `true` if the error is retryable.
1169    pub fn is_retryable(&self) -> bool {
1170        self.retry_hint().is_retryable()
1171    }
1172}
1173
1174pub type Result<T> = std::result::Result<T, Error>;
1175
1176define_into_tonic_status!(Error);
1177
1178impl ErrorExt for Error {
1179    fn status_code(&self) -> StatusCode {
1180        match self {
1181            Error::EtcdFailed { .. }
1182            | Error::ConnectEtcd { .. }
1183            | Error::FileIo { .. }
1184            | Error::TcpBind { .. }
1185            | Error::SerializeConfig { .. }
1186            | Error::SerializeToJson { .. }
1187            | Error::DeserializeFromJson { .. }
1188            | Error::NoLeader { .. }
1189            | Error::LeaderLeaseExpired { .. }
1190            | Error::LeaderLeaseChanged { .. }
1191            | Error::CreateChannel { .. }
1192            | Error::BatchGet { .. }
1193            | Error::Range { .. }
1194            | Error::ResponseHeaderNotFound { .. }
1195            | Error::InvalidHttpBody { .. }
1196            | Error::ExceededRetryLimit { .. }
1197            | Error::SendShutdownSignal { .. }
1198            | Error::PushMessage { .. }
1199            | Error::MailboxClosed { .. }
1200            | Error::MailboxReceiver { .. }
1201            | Error::StartGrpc { .. }
1202            | Error::PublishMessage { .. }
1203            | Error::Join { .. }
1204            | Error::ChooseItems { .. }
1205            | Error::FlowStateHandler { .. }
1206            | Error::BuildWalProvider { .. }
1207            | Error::BuildPartitionClient { .. }
1208            | Error::BuildKafkaClient { .. } => StatusCode::Internal,
1209
1210            Error::DeleteRecords { .. }
1211            | Error::GetOffset { .. }
1212            | Error::PeerUnavailable { .. }
1213            | Error::PusherNotFound { .. } => StatusCode::Unexpected,
1214            Error::MailboxTimeout { .. } | Error::ExceededDeadline { .. } => StatusCode::Cancelled,
1215            Error::PruneTaskAlreadyRunning { .. }
1216            | Error::RetryLater { .. }
1217            | Error::MailboxChannelClosed { .. }
1218            | Error::IsNotLeader { .. } => StatusCode::IllegalState,
1219            Error::RetryLaterWithSource { source, .. } => source.status_code(),
1220            Error::SerializePartitionExpr { source, .. }
1221            | Error::DeserializePartitionExpr { source, .. } => source.status_code(),
1222
1223            Error::Unsupported { .. } => StatusCode::Unsupported,
1224
1225            Error::SchemaAlreadyExists { .. } => StatusCode::DatabaseAlreadyExists,
1226
1227            Error::TableAlreadyExists { .. } => StatusCode::TableAlreadyExists,
1228            Error::EmptyKey { .. }
1229            | Error::MissingRequiredParameter { .. }
1230            | Error::MissingRequestHeader { .. }
1231            | Error::InvalidLeaseKey { .. }
1232            | Error::InvalidStatKey { .. }
1233            | Error::InvalidInactiveRegionKey { .. }
1234            | Error::InvalidNodeSchedulingKey { .. }
1235            | Error::ParseNum { .. }
1236            | Error::ParseBool { .. }
1237            | Error::ParseAddr { .. }
1238            | Error::UnsupportedSelectorType { .. }
1239            | Error::InvalidArguments { .. }
1240            | Error::ManualGcRejectedByMaintenanceMode { .. }
1241            | Error::ProcedureNotFound { .. }
1242            | Error::TooManyPartitions { .. }
1243            | Error::TomlFormat { .. }
1244            | Error::HandlerNotFound { .. }
1245            | Error::LeaderPeerChanged { .. }
1246            | Error::RepartitionSourceRegionMissing { .. }
1247            | Error::RepartitionTargetRegionMissing { .. }
1248            | Error::PartitionExprMismatch { .. }
1249            | Error::RepartitionSourceExprMismatch { .. }
1250            | Error::EmptyPartitionExpr { .. } => StatusCode::InvalidArguments,
1251            Error::LeaseKeyFromUtf8 { .. }
1252            | Error::LeaseValueFromUtf8 { .. }
1253            | Error::InvalidRegionKeyFromUtf8 { .. }
1254            | Error::TableRouteNotFound { .. }
1255            | Error::TableInfoNotFound { .. }
1256            | Error::DatanodeTableNotFound { .. }
1257            | Error::InvalidUtf8Value { .. }
1258            | Error::UnexpectedInstructionReply { .. }
1259            | Error::Unexpected { .. }
1260            | Error::RegionOperatingRace { .. }
1261            | Error::RegionRouteNotFound { .. }
1262            | Error::MigrationAbort { .. }
1263            | Error::MigrationRunning { .. }
1264            | Error::DrainDatanodeRunning { .. }
1265            | Error::RegionMigrated { .. } => StatusCode::Unexpected,
1266            Error::TableNotFound { .. } => StatusCode::TableNotFound,
1267            Error::SaveClusterInfo { source, .. }
1268            | Error::InvalidClusterInfoFormat { source, .. }
1269            | Error::InvalidDatanodeStatFormat { source, .. }
1270            | Error::InvalidNodeInfoFormat { source, .. } => source.status_code(),
1271            Error::InvalidateTableCache { source, .. } => source.status_code(),
1272            Error::SubmitProcedure { source, .. }
1273            | Error::WaitProcedure { source, .. }
1274            | Error::QueryProcedure { source, .. } => source.status_code(),
1275            Error::ShutdownServer { source, .. } | Error::StartHttp { source, .. } => {
1276                source.status_code()
1277            }
1278            Error::StartProcedureManager { source, .. }
1279            | Error::StopProcedureManager { source, .. } => source.status_code(),
1280
1281            Error::ListCatalogs { source, .. }
1282            | Error::ListSchemas { source, .. }
1283            | Error::ListTables { source, .. } => source.status_code(),
1284            Error::StartTelemetryTask { source, .. } => source.status_code(),
1285
1286            Error::NextSequence { source, .. }
1287            | Error::SetNextSequence { source, .. }
1288            | Error::PeekSequence { source, .. } => source.status_code(),
1289            Error::DowngradeLeader { source, .. } => source.status_code(),
1290            Error::RegisterProcedureLoader { source, .. } => source.status_code(),
1291            Error::SubmitDdlTask { source, .. }
1292            | Error::SubmitReconcileProcedure { source, .. } => source.status_code(),
1293            Error::ConvertProtoData { source, .. }
1294            | Error::TableMetadataManager { source, .. }
1295            | Error::RuntimeSwitchManager { source, .. }
1296            | Error::KvBackend { source, .. }
1297            | Error::UnexpectedLogicalRouteTable { source, .. }
1298            | Error::UpdateTopicNameValue { source, .. } => source.status_code(),
1299            Error::ListActiveFrontends { source, .. }
1300            | Error::ListActiveDatanodes { source, .. }
1301            | Error::ListActiveFlownodes { source, .. } => source.status_code(),
1302            Error::NoAvailableFrontend { .. } | Error::RepartitionGcRequired { .. } => {
1303                StatusCode::IllegalState
1304            }
1305
1306            Error::InitMetadata { source, .. }
1307            | Error::InitDdlManager { source, .. }
1308            | Error::InitReconciliationManager { source, .. } => source.status_code(),
1309
1310            Error::BuildTlsOptions { source, .. } => source.status_code(),
1311            Error::Other { source, .. } => source.status_code(),
1312            Error::RepartitionCreateSubtasks { source, .. } => source.status_code(),
1313            Error::RepartitionGcRequirement { source, .. } => source.status_code(),
1314            Error::InspectRepartitionProcedures { source, .. } => source.status_code(),
1315            Error::RepartitionSubprocedureStateReceiver { source, .. } => source.status_code(),
1316            Error::AllocateRegions { source, .. } => source.status_code(),
1317            Error::DeallocateRegions { source, .. } => source.status_code(),
1318            Error::AllocateRegionRoutes { source, .. } => source.status_code(),
1319            Error::AllocateWalOptions { source, .. } => source.status_code(),
1320            Error::BuildCreateRequest { source, .. } => source.status_code(),
1321            Error::NoEnoughAvailableNode { .. } => StatusCode::RuntimeResourcesExhausted,
1322
1323            #[cfg(feature = "pg_kvbackend")]
1324            Error::CreatePostgresPool { .. }
1325            | Error::GetPostgresClient { .. }
1326            | Error::GetPostgresConnection { .. }
1327            | Error::PostgresExecution { .. } => StatusCode::Internal,
1328            #[cfg(feature = "mysql_kvbackend")]
1329            Error::MySqlExecution { .. }
1330            | Error::CreateMySqlPool { .. }
1331            | Error::ParseMySqlUrl { .. }
1332            | Error::DecodeSqlValue { .. }
1333            | Error::AcquireMySqlClient { .. } => StatusCode::Internal,
1334            #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1335            Error::SqlExecutionTimeout { .. } => StatusCode::Internal,
1336        }
1337    }
1338
1339    fn as_any(&self) -> &dyn std::any::Any {
1340        self
1341    }
1342
1343    fn retry_hint(&self) -> RetryHint {
1344        match self {
1345            Error::RetryLater { .. }
1346            | Error::RetryLaterWithSource { .. }
1347            | Error::MailboxTimeout { .. }
1348            | Error::NoEnoughAvailableNode { .. }
1349            | Error::NoLeader { .. }
1350            | Error::LeaderLeaseExpired { .. }
1351            | Error::LeaderLeaseChanged { .. }
1352            | Error::PeerUnavailable { .. } => RetryHint::Retryable,
1353
1354            Error::ConnectEtcd { error, .. } | Error::EtcdFailed { error, .. } => {
1355                common_meta::error::retry_hint_from_etcd_error(error)
1356            }
1357
1358            #[cfg(feature = "pg_kvbackend")]
1359            Error::PostgresExecution { error, .. } => {
1360                common_meta::error::retry_hint_from_postgres_error(error)
1361            }
1362            #[cfg(feature = "pg_kvbackend")]
1363            Error::GetPostgresClient { error, .. } => {
1364                common_meta::error::retry_hint_from_postgres_pool_error(error)
1365            }
1366            #[cfg(feature = "mysql_kvbackend")]
1367            Error::MySqlExecution { error, .. }
1368            | Error::CreateMySqlPool { error, .. }
1369            | Error::AcquireMySqlClient { error, .. } => {
1370                common_meta::error::retry_hint_from_sqlx_error(error)
1371            }
1372            #[cfg(any(feature = "pg_kvbackend", feature = "mysql_kvbackend"))]
1373            Error::SqlExecutionTimeout { .. } => RetryHint::Retryable,
1374
1375            Error::ListActiveFrontends { source, .. }
1376            | Error::ListActiveDatanodes { source, .. }
1377            | Error::ListActiveFlownodes { source, .. }
1378            | Error::InitDdlManager { source, .. }
1379            | Error::InitReconciliationManager { source, .. }
1380            | Error::InitMetadata { source, .. }
1381            | Error::NextSequence { source, .. }
1382            | Error::SetNextSequence { source, .. }
1383            | Error::PeekSequence { source, .. }
1384            | Error::SubmitDdlTask { source, .. }
1385            | Error::SubmitReconcileProcedure { source, .. }
1386            | Error::InvalidateTableCache { source, .. }
1387            | Error::ConvertProtoData { source, .. }
1388            | Error::TableMetadataManager { source, .. }
1389            | Error::RuntimeSwitchManager { source, .. }
1390            | Error::KvBackend { source, .. }
1391            | Error::UnexpectedLogicalRouteTable { source, .. }
1392            | Error::SaveClusterInfo { source, .. }
1393            | Error::InvalidClusterInfoFormat { source, .. }
1394            | Error::InvalidDatanodeStatFormat { source, .. }
1395            | Error::InvalidNodeInfoFormat { source, .. }
1396            | Error::FlowStateHandler { source, .. }
1397            | Error::BuildWalProvider { source, .. }
1398            | Error::BuildKafkaClient { error: source, .. }
1399            | Error::UpdateTopicNameValue { source, .. }
1400            | Error::BuildTlsOptions { source, .. }
1401            | Error::AllocateRegions { source, .. }
1402            | Error::DeallocateRegions { source, .. }
1403            | Error::BuildCreateRequest { source, .. }
1404            | Error::AllocateRegionRoutes { source, .. }
1405            | Error::AllocateWalOptions { source, .. }
1406            | Error::RepartitionGcRequirement { source, .. } => source.retry_hint(),
1407
1408            Error::Other { source, .. }
1409            | Error::ListCatalogs { source, .. }
1410            | Error::ListSchemas { source, .. }
1411            | Error::ListTables { source, .. }
1412            | Error::DowngradeLeader { source, .. } => source.retry_hint(),
1413
1414            Error::SubmitProcedure { source, .. }
1415            | Error::WaitProcedure { source, .. }
1416            | Error::QueryProcedure { source, .. }
1417            | Error::StartProcedureManager { source, .. }
1418            | Error::StopProcedureManager { source, .. }
1419            | Error::RegisterProcedureLoader { source, .. }
1420            | Error::InspectRepartitionProcedures { source, .. }
1421            | Error::RepartitionSubprocedureStateReceiver { source, .. } => source.retry_hint(),
1422
1423            Error::ShutdownServer { source, .. } | Error::StartHttp { source, .. } => {
1424                source.retry_hint()
1425            }
1426            Error::StartTelemetryTask { source, .. } => source.retry_hint(),
1427            Error::CreateChannel { source, .. } => source.retry_hint(),
1428            Error::RepartitionCreateSubtasks { source, .. } => source.retry_hint(),
1429            Error::SerializePartitionExpr { source, .. }
1430            | Error::DeserializePartitionExpr { source, .. } => source.retry_hint(),
1431
1432            Error::DeleteRecords { error, .. }
1433            | Error::BuildPartitionClient { error, .. }
1434            | Error::GetOffset { error, .. } => rskafka_client_error_to_retry_hint(error),
1435
1436            Error::PusherNotFound { .. }
1437            | Error::PushMessage { .. }
1438            | Error::ExceededDeadline { .. } => RetryHint::NonRetryable,
1439
1440            _ => RetryHint::NonRetryable,
1441        }
1442    }
1443}
1444
1445// for form tonic
1446pub(crate) fn match_for_io_error(err_status: &tonic::Status) -> Option<&std::io::Error> {
1447    let mut err: &(dyn std::error::Error + 'static) = err_status;
1448
1449    loop {
1450        if let Some(io_err) = err.downcast_ref::<std::io::Error>() {
1451            return Some(io_err);
1452        }
1453
1454        // h2::Error do not expose std::io::Error with `source()`
1455        // https://github.com/hyperium/h2/pull/462
1456        if let Some(h2_err) = err.downcast_ref::<h2::Error>()
1457            && let Some(io_err) = h2_err.get_io()
1458        {
1459            return Some(io_err);
1460        }
1461
1462        err = err.source()?;
1463    }
1464}
1465
1466#[cfg(test)]
1467mod tests {
1468    use std::time::Duration;
1469
1470    use common_error::ext::ErrorExt;
1471    use common_error::mock::MockError;
1472    use common_error::status_code::StatusCode;
1473    use rskafka::BackoffError;
1474    use rskafka::client::error::Error as KafkaClientError;
1475    use snafu::ResultExt;
1476
1477    use super::{
1478        BuildPartitionClientSnafu, DeallocateRegionsSnafu, DeleteRecordsSnafu, GetOffsetSnafu,
1479    };
1480
1481    fn retry_failed_kafka_error() -> KafkaClientError {
1482        KafkaClientError::RetryFailed(BackoffError::DeadlineExceded {
1483            deadline: Duration::from_secs(1),
1484            source: Box::new(std::io::Error::other("retry failed")),
1485        })
1486    }
1487
1488    #[test]
1489    fn test_deallocate_regions_is_retryable_when_source_is_retry_later() {
1490        let source = common_meta::error::Error::retry_later(MockError::new(StatusCode::Internal));
1491        let err = Err::<(), _>(source)
1492            .context(DeallocateRegionsSnafu { table_id: 1024_u32 })
1493            .unwrap_err();
1494
1495        assert!(err.is_retryable());
1496        assert!(err.retry_hint().is_retryable());
1497    }
1498
1499    #[test]
1500    fn test_deallocate_regions_is_not_retryable_when_source_is_not_retry_later() {
1501        let source = common_meta::error::UnexpectedSnafu {
1502            err_msg: "mock error",
1503        }
1504        .build();
1505        let err = Err::<(), _>(source)
1506            .context(DeallocateRegionsSnafu { table_id: 1024_u32 })
1507            .unwrap_err();
1508
1509        assert!(!err.is_retryable());
1510        assert!(!err.retry_hint().is_retryable());
1511    }
1512
1513    #[test]
1514    fn test_kafka_retry_failed_errors_are_retryable() {
1515        let delete_records_err = Err::<(), _>(retry_failed_kafka_error())
1516            .context(DeleteRecordsSnafu {
1517                topic: "test_topic",
1518                partition: 0,
1519                offset: 1024u64,
1520            })
1521            .unwrap_err();
1522        let build_partition_client_err = Err::<(), _>(retry_failed_kafka_error())
1523            .context(BuildPartitionClientSnafu {
1524                topic: "test_topic",
1525                partition: 0,
1526            })
1527            .unwrap_err();
1528        let get_offset_err = Err::<(), _>(retry_failed_kafka_error())
1529            .context(GetOffsetSnafu {
1530                topic: "test_topic",
1531            })
1532            .unwrap_err();
1533
1534        assert!(delete_records_err.is_retryable());
1535        assert!(build_partition_client_err.is_retryable());
1536        assert!(get_offset_err.is_retryable());
1537        assert!(delete_records_err.retry_hint().is_retryable());
1538        assert!(build_partition_client_err.retry_hint().is_retryable());
1539        assert!(get_offset_err.retry_hint().is_retryable());
1540    }
1541
1542    #[test]
1543    fn test_kafka_non_retry_failed_errors_are_not_retryable() {
1544        let delete_records_err = Err::<(), _>(KafkaClientError::InvalidResponse("invalid".into()))
1545            .context(DeleteRecordsSnafu {
1546                topic: "test_topic",
1547                partition: 0,
1548                offset: 1024u64,
1549            })
1550            .unwrap_err();
1551        let build_partition_client_err =
1552            Err::<(), _>(KafkaClientError::InvalidResponse("invalid".into()))
1553                .context(BuildPartitionClientSnafu {
1554                    topic: "test_topic",
1555                    partition: 0,
1556                })
1557                .unwrap_err();
1558        let get_offset_err = Err::<(), _>(KafkaClientError::InvalidResponse("invalid".into()))
1559            .context(GetOffsetSnafu {
1560                topic: "test_topic",
1561            })
1562            .unwrap_err();
1563
1564        assert!(!delete_records_err.is_retryable());
1565        assert!(!build_partition_client_err.is_retryable());
1566        assert!(!get_offset_err.is_retryable());
1567        assert!(!delete_records_err.retry_hint().is_retryable());
1568        assert!(!build_partition_client_err.retry_hint().is_retryable());
1569        assert!(!get_offset_err.retry_hint().is_retryable());
1570    }
1571}