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