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