Skip to main content

mito2/
error.rs

1// Copyright 2023 Greptime Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::any::Any;
16use std::sync::Arc;
17
18use common_datasource::compression::CompressionType;
19use common_error::ext::{BoxedError, ErrorExt, RetryHint};
20use common_error::status_code::StatusCode;
21use common_macro::stack_trace_debug;
22use common_memory_manager;
23use common_runtime::JoinError;
24use common_time::Timestamp;
25use common_time::timestamp::TimeUnit;
26use datatypes::arrow::error::ArrowError;
27use datatypes::prelude::ConcreteDataType;
28use object_store::ErrorKind;
29use object_store::error::retry_hint_from_opendal_error;
30use partition::error::Error as PartitionError;
31use prost::DecodeError;
32use snafu::{Location, Snafu};
33use store_api::ManifestVersion;
34use store_api::logstore::provider::Provider;
35use store_api::storage::{FileId, RegionId};
36use tokio::time::error::Elapsed;
37
38use crate::cache::file_cache::FileType;
39use crate::region::RegionRoleState;
40use crate::schedule::remote_job_scheduler::JobId;
41use crate::worker::WorkerId;
42
43#[derive(Snafu)]
44#[snafu(visibility(pub))]
45#[stack_trace_debug]
46pub enum Error {
47    #[cfg(feature = "enterprise")]
48    #[snafu(display("Failed to route multi-region compaction input"))]
49    RouteMultiRegion {
50        #[snafu(source)]
51        source: PartitionError,
52        #[snafu(implicit)]
53        location: Location,
54    },
55
56    #[cfg(feature = "enterprise")]
57    #[snafu(display("Invalid multi-region compaction: {reason}"))]
58    InvalidMultiRegionCompaction {
59        reason: String,
60        #[snafu(implicit)]
61        location: Location,
62    },
63
64    #[cfg(feature = "enterprise")]
65    #[snafu(display("Multi-region compaction resource limit: {reason}"))]
66    MultiRegionCompactionResource {
67        reason: String,
68        #[snafu(implicit)]
69        location: Location,
70    },
71
72    #[snafu(display("SST writer {kind} needs {bytes} bytes, budget is {limit}"))]
73    SstWriteMemoryExceeded {
74        kind: &'static str,
75        bytes: usize,
76        limit: usize,
77        #[snafu(implicit)]
78        location: Location,
79    },
80
81    #[snafu(display("Unexpected data type"))]
82    DataTypeMismatch {
83        source: datatypes::error::Error,
84        #[snafu(implicit)]
85        location: Location,
86    },
87
88    #[snafu(display("External error, context: {}", context))]
89    External {
90        source: BoxedError,
91        context: String,
92        #[snafu(implicit)]
93        location: Location,
94    },
95
96    #[snafu(display("OpenDAL operator failed"))]
97    OpenDal {
98        #[snafu(implicit)]
99        location: Location,
100        #[snafu(source)]
101        error: object_store::Error,
102    },
103
104    #[snafu(display(
105        "Manifest delta {} disappeared after it was listed, path: {}",
106        version,
107        path
108    ))]
109    ManifestDeltaNotFound {
110        version: ManifestVersion,
111        path: String,
112        #[snafu(source)]
113        error: object_store::Error,
114        #[snafu(implicit)]
115        location: Location,
116    },
117
118    #[snafu(display("Fail to compress object by {}, path: {}", compress_type, path))]
119    CompressObject {
120        compress_type: CompressionType,
121        path: String,
122        #[snafu(source)]
123        error: std::io::Error,
124    },
125
126    #[snafu(display("Fail to decompress object by {}, path: {}", compress_type, path))]
127    DecompressObject {
128        compress_type: CompressionType,
129        path: String,
130        #[snafu(source)]
131        error: std::io::Error,
132    },
133
134    #[snafu(display("Failed to ser/de json object"))]
135    SerdeJson {
136        #[snafu(implicit)]
137        location: Location,
138        #[snafu(source)]
139        error: serde_json::Error,
140    },
141
142    #[snafu(display("Failed to serialize column metadata"))]
143    SerializeColumnMetadata {
144        #[snafu(source)]
145        error: serde_json::Error,
146        #[snafu(implicit)]
147        location: Location,
148    },
149
150    #[snafu(display("Manifest version {version} conflicts in {manifest_dir}: {reason}"))]
151    ManifestVersionConflict {
152        version: ManifestVersion,
153        manifest_dir: String,
154        reason: String,
155        #[snafu(implicit)]
156        location: Location,
157    },
158
159    #[snafu(display(
160        "Manifest checkpoint {version} in {manifest_dir} was removed after it was listed"
161    ))]
162    ManifestCheckpointVanished {
163        version: ManifestVersion,
164        manifest_dir: String,
165        #[snafu(implicit)]
166        location: Location,
167    },
168
169    #[snafu(display("Failed to serialize manifest, region_id: {}", region_id))]
170    SerializeManifest {
171        region_id: RegionId,
172        #[snafu(source)]
173        error: serde_json::Error,
174        #[snafu(implicit)]
175        location: Location,
176    },
177
178    #[snafu(display("Invalid scan index, start: {}, end: {}", start, end))]
179    InvalidScanIndex {
180        start: ManifestVersion,
181        end: ManifestVersion,
182        #[snafu(implicit)]
183        location: Location,
184    },
185
186    #[snafu(display("Invalid UTF-8 content"))]
187    Utf8 {
188        #[snafu(implicit)]
189        location: Location,
190        #[snafu(source)]
191        error: std::str::Utf8Error,
192    },
193
194    #[snafu(display("Cannot find RegionMetadata"))]
195    RegionMetadataNotFound {
196        #[snafu(implicit)]
197        location: Location,
198    },
199
200    #[snafu(display("Failed to join handle"))]
201    Join {
202        #[snafu(source)]
203        error: common_runtime::JoinError,
204        #[snafu(implicit)]
205        location: Location,
206    },
207
208    #[snafu(display("Worker {} is stopped", id))]
209    WorkerStopped {
210        id: WorkerId,
211        #[snafu(implicit)]
212        location: Location,
213    },
214
215    #[snafu(display("Engine is stopped"))]
216    EngineStopped {
217        #[snafu(implicit)]
218        location: Location,
219    },
220
221    #[snafu(display("Failed to recv result"))]
222    Recv {
223        #[snafu(source)]
224        error: tokio::sync::oneshot::error::RecvError,
225        #[snafu(implicit)]
226        location: Location,
227    },
228
229    #[snafu(display("Invalid metadata, {}", reason))]
230    InvalidMeta {
231        reason: String,
232        #[snafu(implicit)]
233        location: Location,
234    },
235
236    #[snafu(display("Invalid region metadata"))]
237    InvalidMetadata {
238        source: store_api::metadata::MetadataError,
239        #[snafu(implicit)]
240        location: Location,
241    },
242
243    #[snafu(display("Failed to create RecordBatch from vectors"))]
244    NewRecordBatch {
245        #[snafu(implicit)]
246        location: Location,
247        #[snafu(source)]
248        error: ArrowError,
249    },
250
251    #[snafu(display("Failed to read parquet file, path: {}", path))]
252    ReadParquet {
253        path: String,
254        #[snafu(source)]
255        error: parquet::errors::ParquetError,
256        #[snafu(implicit)]
257        location: Location,
258    },
259
260    #[snafu(display("Failed to load range result"))]
261    LoadRangeResult {
262        source: Arc<Error>,
263        #[snafu(implicit)]
264        location: Location,
265    },
266
267    #[snafu(display("Failed to load SST metadata"))]
268    LoadSstMeta {
269        source: Arc<Error>,
270        #[snafu(implicit)]
271        location: Location,
272    },
273
274    #[snafu(display("Failed to load Parquet page"))]
275    LoadParquetPage {
276        source: Arc<Error>,
277        #[snafu(implicit)]
278        location: Location,
279    },
280
281    #[snafu(display("Failed to write parquet file"))]
282    WriteParquet {
283        #[snafu(source)]
284        error: parquet::errors::ParquetError,
285        #[snafu(implicit)]
286        location: Location,
287    },
288
289    #[snafu(display(
290        "Cannot assign a stable field id to native histogram sub-field '{}' of column id {} (unknown sub-field name or derived id overflows i32)",
291        field_name,
292        column_id
293    ))]
294    InvalidNativeHistogramSubfield {
295        column_id: i32,
296        field_name: String,
297        #[snafu(implicit)]
298        location: Location,
299    },
300
301    #[snafu(display(
302        "Native histogram column '{}' has no usable PARQUET:field_id to namespace its sub-field ids (missing, malformed, or exceeds i32::MAX)",
303        field_name
304    ))]
305    InvalidNativeHistogramFieldId {
306        field_name: String,
307        #[snafu(implicit)]
308        location: Location,
309    },
310
311    #[snafu(display("Region {} not found", region_id))]
312    RegionNotFound {
313        region_id: RegionId,
314        #[snafu(implicit)]
315        location: Location,
316    },
317
318    #[snafu(display("Object store not found: {}", object_store))]
319    ObjectStoreNotFound {
320        object_store: String,
321        #[snafu(implicit)]
322        location: Location,
323    },
324
325    #[snafu(display("Region {} is corrupted, reason: {}", region_id, reason))]
326    RegionCorrupted {
327        region_id: RegionId,
328        reason: String,
329        #[snafu(implicit)]
330        location: Location,
331    },
332
333    #[snafu(display("Invalid request to region {}, reason: {}", region_id, reason))]
334    InvalidRequest {
335        region_id: RegionId,
336        reason: String,
337        #[snafu(implicit)]
338        location: Location,
339    },
340
341    #[snafu(display(
342        "STALE_CURSOR: incremental query stale, region: {}, given_seq: {}, min_readable_seq: {}, retry_hint: FALLBACK_FULL_RECOMPUTE",
343        region_id,
344        given_seq,
345        min_readable_seq
346    ))]
347    IncrementalQueryStale {
348        region_id: RegionId,
349        given_seq: u64,
350        min_readable_seq: u64,
351        #[snafu(implicit)]
352        location: Location,
353    },
354
355    #[snafu(display(
356        "STALE_SNAPSHOT_FENCE: snapshot upper bound stale, region: {}, given_seq: {}, min_enforceable_seq: {}, retry_hint: REBIND_SNAPSHOT_FENCE",
357        region_id,
358        given_seq,
359        min_enforceable_seq
360    ))]
361    SnapshotFenceStale {
362        region_id: RegionId,
363        given_seq: u64,
364        min_enforceable_seq: u64,
365        #[snafu(implicit)]
366        location: Location,
367    },
368
369    #[snafu(display(
370        "SEQUENCE_RANGE_UNSUPPORTED: exact sequence-range read unsupported, region: {}, min_seq: {}, max_seq: {}, reason: {}, retry_hint: FALLBACK_MEMTABLE_ONLY_OR_FULL_RECOMPUTE",
371        region_id,
372        min_seq,
373        max_seq,
374        reason
375    ))]
376    SequenceRangeUnsupported {
377        region_id: RegionId,
378        min_seq: u64,
379        max_seq: u64,
380        reason: String,
381        #[snafu(implicit)]
382        location: Location,
383    },
384
385    #[snafu(display(
386        "region {} is unusable for sequence reads: file {} declares region {}",
387        region_id,
388        file_id,
389        file_region_id
390    ))]
391    RegionSequenceDomainBroken {
392        region_id: RegionId,
393        file_region_id: RegionId,
394        file_id: FileId,
395        #[snafu(implicit)]
396        location: Location,
397    },
398
399    #[snafu(display("Old manifest missing for region {}", region_id))]
400    MissingOldManifest {
401        region_id: RegionId,
402        #[snafu(implicit)]
403        location: Location,
404    },
405
406    #[snafu(display("New manifest missing for region {}", region_id))]
407    MissingNewManifest {
408        region_id: RegionId,
409        #[snafu(implicit)]
410        location: Location,
411    },
412
413    #[snafu(display("Manifest missing for region {}", region_id))]
414    MissingManifest {
415        region_id: RegionId,
416        #[snafu(implicit)]
417        location: Location,
418    },
419
420    #[snafu(display("File consistency check failed for file {}: {}", file_id, reason))]
421    InconsistentFile {
422        file_id: FileId,
423        reason: String,
424        #[snafu(implicit)]
425        location: Location,
426    },
427
428    #[snafu(display("Files lost during remapping: old={}, new={}", old_count, new_count))]
429    FilesLost {
430        old_count: usize,
431        new_count: usize,
432        #[snafu(implicit)]
433        location: Location,
434    },
435
436    #[snafu(display("No old manifests provided (need at least one for template)"))]
437    NoOldManifests {
438        #[snafu(implicit)]
439        location: Location,
440    },
441
442    #[snafu(display("Failed to fetch manifests"))]
443    FetchManifests {
444        #[snafu(implicit)]
445        location: Location,
446        source: BoxedError,
447    },
448
449    #[snafu(display("Partition expression missing for region {}", region_id))]
450    MissingPartitionExpr {
451        region_id: RegionId,
452        #[snafu(implicit)]
453        location: Location,
454    },
455
456    #[snafu(display("Failed to serialize partition expression: {}", source))]
457    SerializePartitionExpr {
458        #[snafu(source)]
459        source: PartitionError,
460        #[snafu(implicit)]
461        location: Location,
462    },
463
464    #[snafu(display(
465        "Failed to convert ConcreteDataType to ColumnDataType, reason: {}",
466        reason
467    ))]
468    ConvertColumnDataType {
469        reason: String,
470        source: api::error::Error,
471        #[snafu(implicit)]
472        location: Location,
473    },
474
475    /// An error type to indicate that schema is changed and we need
476    /// to fill default values again.
477    #[snafu(display("Need to fill default value for region {}", region_id))]
478    FillDefault {
479        region_id: RegionId,
480        // The error is for internal use so we don't need a location.
481    },
482
483    #[snafu(display(
484        "Failed to create default value for column {} of region {}",
485        column,
486        region_id
487    ))]
488    CreateDefault {
489        region_id: RegionId,
490        column: String,
491        source: datatypes::Error,
492        #[snafu(implicit)]
493        location: Location,
494    },
495
496    #[snafu(display("Failed to build entry, region_id: {}", region_id))]
497    BuildEntry {
498        region_id: RegionId,
499        #[snafu(implicit)]
500        location: Location,
501        source: BoxedError,
502    },
503
504    #[snafu(display("Failed to write WAL"))]
505    WriteWal {
506        #[snafu(implicit)]
507        location: Location,
508        source: BoxedError,
509    },
510
511    #[snafu(display("Failed to read WAL, provider: {}", provider))]
512    ReadWal {
513        provider: Provider,
514        #[snafu(implicit)]
515        location: Location,
516        source: BoxedError,
517    },
518
519    #[snafu(display("Failed to decode WAL entry, region_id: {}", region_id))]
520    DecodeWal {
521        region_id: RegionId,
522        #[snafu(implicit)]
523        location: Location,
524        #[snafu(source)]
525        error: DecodeError,
526    },
527
528    #[snafu(display("Failed to delete WAL, region_id: {}", region_id))]
529    DeleteWal {
530        region_id: RegionId,
531        #[snafu(implicit)]
532        location: Location,
533        source: BoxedError,
534    },
535
536    #[snafu(display("Failed to wait for the WAL to be durable, region_id: {}", region_id))]
537    WaitWalDurable {
538        region_id: RegionId,
539        #[snafu(implicit)]
540        location: Location,
541        source: BoxedError,
542    },
543
544    #[snafu(display("Failed to check the WAL history, region_id: {}", region_id))]
545    CheckWalHistory {
546        region_id: RegionId,
547        #[snafu(implicit)]
548        location: Location,
549        source: BoxedError,
550    },
551
552    // Shared error for each writer in the write group.
553    #[snafu(display("Failed to write region"))]
554    WriteGroup { source: Arc<Error> },
555
556    #[snafu(display("Invalid parquet SST file {}, reason: {}", file, reason))]
557    InvalidParquet {
558        file: String,
559        reason: String,
560        #[snafu(implicit)]
561        location: Location,
562    },
563
564    #[snafu(display("Invalid batch, {}", reason))]
565    InvalidBatch {
566        reason: String,
567        #[snafu(implicit)]
568        location: Location,
569    },
570
571    #[snafu(display("Invalid arrow record batch, {}", reason))]
572    InvalidRecordBatch {
573        reason: String,
574        #[snafu(implicit)]
575        location: Location,
576    },
577
578    #[snafu(display("Invalid wal read request, {}", reason))]
579    InvalidWalReadRequest {
580        reason: String,
581        #[snafu(implicit)]
582        location: Location,
583    },
584
585    #[snafu(display("Failed to convert array to vector"))]
586    ConvertVector {
587        #[snafu(implicit)]
588        location: Location,
589        source: datatypes::error::Error,
590    },
591
592    #[snafu(display("Failed to compute arrow arrays"))]
593    ComputeArrow {
594        #[snafu(implicit)]
595        location: Location,
596        #[snafu(source)]
597        error: datatypes::arrow::error::ArrowError,
598    },
599
600    #[snafu(display("Failed to evaluate partition filter"))]
601    EvalPartitionFilter {
602        #[snafu(implicit)]
603        location: Location,
604        #[snafu(source)]
605        error: datafusion::error::DataFusionError,
606    },
607
608    #[snafu(display("Failed to merge candidate series"))]
609    MergeCandidateSeries {
610        #[snafu(implicit)]
611        location: Location,
612        #[snafu(source)]
613        error: datafusion::error::DataFusionError,
614    },
615
616    #[snafu(display("Failed to compute vector"))]
617    ComputeVector {
618        #[snafu(implicit)]
619        location: Location,
620        source: datatypes::error::Error,
621    },
622
623    #[snafu(display("Primary key length mismatch, expect: {}, actual: {}", expect, actual))]
624    PrimaryKeyLengthMismatch {
625        expect: usize,
626        actual: usize,
627        #[snafu(implicit)]
628        location: Location,
629    },
630
631    #[snafu(display("Invalid sender",))]
632    InvalidSender {
633        #[snafu(implicit)]
634        location: Location,
635    },
636
637    #[snafu(display("Invalid scheduler state"))]
638    InvalidSchedulerState {
639        #[snafu(implicit)]
640        location: Location,
641    },
642
643    #[snafu(display("Failed to stop scheduler"))]
644    StopScheduler {
645        #[snafu(source)]
646        error: JoinError,
647        #[snafu(implicit)]
648        location: Location,
649    },
650
651    #[snafu(display(
652        "Failed to batch delete SST files, region id: {}, file ids: {:?}",
653        region_id,
654        file_ids
655    ))]
656    DeleteSsts {
657        region_id: RegionId,
658        file_ids: Vec<FileId>,
659        #[snafu(source)]
660        error: object_store::Error,
661        #[snafu(implicit)]
662        location: Location,
663    },
664
665    #[snafu(display("Failed to delete index file, file id: {}", file_id))]
666    DeleteIndex {
667        file_id: FileId,
668        #[snafu(source)]
669        error: object_store::Error,
670        #[snafu(implicit)]
671        location: Location,
672    },
673
674    #[snafu(display("Failed to batch delete index files, file ids: {:?}", file_ids))]
675    DeleteIndexes {
676        file_ids: Vec<FileId>,
677        #[snafu(source)]
678        error: object_store::Error,
679        #[snafu(implicit)]
680        location: Location,
681    },
682
683    #[snafu(display("Failed to flush region {}", region_id))]
684    FlushRegion {
685        region_id: RegionId,
686        source: Arc<Error>,
687        #[snafu(implicit)]
688        location: Location,
689    },
690
691    #[snafu(display("Region {} is dropped", region_id))]
692    RegionDropped {
693        region_id: RegionId,
694        #[snafu(implicit)]
695        location: Location,
696    },
697
698    #[snafu(display("Region {} is closed", region_id))]
699    RegionClosed {
700        region_id: RegionId,
701        #[snafu(implicit)]
702        location: Location,
703    },
704
705    #[snafu(display(
706        "Stale compaction execution for region {}, the region may have been reopened, truncated or the compaction was superseded",
707        region_id
708    ))]
709    StaleCompactionExecution {
710        region_id: RegionId,
711        #[snafu(implicit)]
712        location: Location,
713    },
714
715    #[snafu(display("Region {} is truncated", region_id))]
716    RegionTruncated {
717        region_id: RegionId,
718        #[snafu(implicit)]
719        location: Location,
720    },
721
722    #[snafu(display(
723        "Engine write buffer is full, rejecting write requests of region {}",
724        region_id,
725    ))]
726    RejectWrite {
727        region_id: RegionId,
728        #[snafu(implicit)]
729        location: Location,
730    },
731
732    #[snafu(display("Region {} rejects writes while in staging", region_id))]
733    RejectWriteInStaging {
734        region_id: RegionId,
735        #[snafu(implicit)]
736        location: Location,
737    },
738
739    #[snafu(display("Region {} still has WAL tails to recover", region_id))]
740    RegionPendingTails {
741        region_id: RegionId,
742        #[snafu(implicit)]
743        location: Location,
744    },
745
746    #[snafu(display("Region {} does not hold a valid leader lease", region_id))]
747    RegionLeaseExpired {
748        region_id: RegionId,
749        #[snafu(implicit)]
750        location: Location,
751    },
752
753    #[snafu(display(
754        "Region {} lost its leader lease while writing to the WAL, the write may have been applied",
755        region_id
756    ))]
757    UnacknowledgedWrite {
758        region_id: RegionId,
759        #[snafu(implicit)]
760        location: Location,
761    },
762
763    #[snafu(display("Failed to compact region {}", region_id))]
764    CompactRegion {
765        region_id: RegionId,
766        source: Arc<Error>,
767        #[snafu(implicit)]
768        location: Location,
769    },
770
771    #[snafu(display("Failed to edit region {}", region_id))]
772    EditRegion {
773        region_id: RegionId,
774        source: Arc<Error>,
775        #[snafu(implicit)]
776        location: Location,
777    },
778
779    #[snafu(display(
780        "Failed to compat readers for region {}, reason: {}",
781        region_id,
782        reason,
783    ))]
784    CompatReader {
785        region_id: RegionId,
786        reason: String,
787        #[snafu(implicit)]
788        location: Location,
789    },
790
791    #[snafu(display("Invalue region req"))]
792    InvalidRegionRequest {
793        source: store_api::metadata::MetadataError,
794        #[snafu(implicit)]
795        location: Location,
796    },
797
798    #[snafu(display(
799        "Region {} is in {:?} state, which does not permit manifest updates.",
800        region_id,
801        state
802    ))]
803    UpdateManifest {
804        region_id: RegionId,
805        state: RegionRoleState,
806        #[snafu(implicit)]
807        location: Location,
808    },
809
810    #[snafu(display("Region {} is in {:?} state, expect: {:?}", region_id, state, expect))]
811    RegionState {
812        region_id: RegionId,
813        state: RegionRoleState,
814        expect: RegionRoleState,
815        #[snafu(implicit)]
816        location: Location,
817    },
818
819    #[snafu(display(
820        "Partition expr version mismatch for region {}: request {}, expected {}",
821        region_id,
822        request_version,
823        expected_version
824    ))]
825    PartitionExprVersionMismatch {
826        region_id: RegionId,
827        request_version: u64,
828        expected_version: u64,
829        #[snafu(implicit)]
830        location: Location,
831    },
832
833    #[snafu(display("Invalid options"))]
834    JsonOptions {
835        #[snafu(source)]
836        error: serde_json::Error,
837        #[snafu(implicit)]
838        location: Location,
839    },
840
841    #[snafu(display(
842        "Empty region directory, region_id: {}, region_dir: {}",
843        region_id,
844        region_dir,
845    ))]
846    EmptyRegionDir {
847        region_id: RegionId,
848        region_dir: String,
849        #[snafu(implicit)]
850        location: Location,
851    },
852
853    #[snafu(display("Empty manifest directory, manifest_dir: {}", manifest_dir,))]
854    EmptyManifestDir {
855        manifest_dir: String,
856        #[snafu(implicit)]
857        location: Location,
858    },
859
860    #[snafu(display("Column not found, column: {column}"))]
861    ColumnNotFound {
862        column: String,
863        #[snafu(implicit)]
864        location: Location,
865    },
866
867    #[snafu(display("Failed to build index applier"))]
868    BuildIndexApplier {
869        source: index::inverted_index::error::Error,
870        #[snafu(implicit)]
871        location: Location,
872    },
873
874    #[snafu(display("Failed to build index asynchronously in region {}", region_id))]
875    BuildIndexAsync {
876        region_id: RegionId,
877        source: Arc<Error>,
878        #[snafu(implicit)]
879        location: Location,
880    },
881
882    #[snafu(display(
883        "Index build did not complete for files {:?} in region {}",
884        file_ids,
885        region_id
886    ))]
887    IndexBuildIncomplete {
888        region_id: RegionId,
889        file_ids: Vec<FileId>,
890        #[snafu(implicit)]
891        location: Location,
892    },
893
894    #[snafu(display("Failed to convert value"))]
895    ConvertValue {
896        source: datatypes::error::Error,
897        #[snafu(implicit)]
898        location: Location,
899    },
900
901    #[snafu(display("Failed to apply inverted index"))]
902    ApplyInvertedIndex {
903        source: index::inverted_index::error::Error,
904        #[snafu(implicit)]
905        location: Location,
906    },
907
908    #[snafu(display("Failed to apply bloom filter index"))]
909    ApplyBloomFilterIndex {
910        source: index::bloom_filter::error::Error,
911        #[snafu(implicit)]
912        location: Location,
913    },
914
915    #[snafu(display("Failed to push index value"))]
916    PushIndexValue {
917        source: index::inverted_index::error::Error,
918        #[snafu(implicit)]
919        location: Location,
920    },
921
922    #[snafu(display("Failed to write index completely"))]
923    IndexFinish {
924        source: index::inverted_index::error::Error,
925        #[snafu(implicit)]
926        location: Location,
927    },
928
929    #[snafu(display("Operate on aborted index"))]
930    OperateAbortedIndex {
931        #[snafu(implicit)]
932        location: Location,
933    },
934
935    #[snafu(display("Failed to read puffin blob"))]
936    PuffinReadBlob {
937        source: puffin::error::Error,
938        #[snafu(implicit)]
939        location: Location,
940    },
941
942    #[snafu(display("Failed to add blob to puffin file"))]
943    PuffinAddBlob {
944        source: puffin::error::Error,
945        #[snafu(implicit)]
946        location: Location,
947    },
948
949    #[snafu(display("Failed to clean dir {dir}"))]
950    CleanDir {
951        dir: String,
952        #[snafu(source)]
953        error: std::io::Error,
954        #[snafu(implicit)]
955        location: Location,
956    },
957
958    #[snafu(display("Invalid config, {reason}"))]
959    InvalidConfig {
960        reason: String,
961        #[snafu(implicit)]
962        location: Location,
963    },
964
965    #[snafu(display(
966        "Stale log entry found during replay, region: {}, flushed: {}, replayed: {}",
967        region_id,
968        flushed_entry_id,
969        unexpected_entry_id
970    ))]
971    StaleLogEntry {
972        region_id: RegionId,
973        flushed_entry_id: u64,
974        unexpected_entry_id: u64,
975    },
976
977    #[snafu(display(
978        "Failed to download file, region_id: {}, file_id: {}, file_type: {:?}",
979        region_id,
980        file_id,
981        file_type,
982    ))]
983    Download {
984        region_id: RegionId,
985        file_id: FileId,
986        file_type: FileType,
987        #[snafu(source)]
988        error: std::io::Error,
989        #[snafu(implicit)]
990        location: Location,
991    },
992
993    #[snafu(display(
994        "Failed to upload file, region_id: {}, file_id: {}, file_type: {:?}",
995        region_id,
996        file_id,
997        file_type,
998    ))]
999    Upload {
1000        region_id: RegionId,
1001        file_id: FileId,
1002        file_type: FileType,
1003        #[snafu(source)]
1004        error: std::io::Error,
1005        #[snafu(implicit)]
1006        location: Location,
1007    },
1008
1009    #[snafu(display("Failed to create directory {}", dir))]
1010    CreateDir {
1011        dir: String,
1012        #[snafu(source)]
1013        error: std::io::Error,
1014    },
1015
1016    #[snafu(display("Record batch error"))]
1017    RecordBatch {
1018        source: common_recordbatch::error::Error,
1019        #[snafu(implicit)]
1020        location: Location,
1021    },
1022
1023    #[snafu(display("BiErrors, first: {first}, second: {second}"))]
1024    BiErrors {
1025        first: Box<Error>,
1026        second: Box<Error>,
1027        #[snafu(implicit)]
1028        location: Location,
1029    },
1030
1031    #[snafu(display("Encode null value"))]
1032    IndexEncodeNull {
1033        #[snafu(implicit)]
1034        location: Location,
1035    },
1036
1037    #[snafu(display("Failed to encode memtable to Parquet bytes"))]
1038    EncodeMemtable {
1039        #[snafu(source)]
1040        error: parquet::errors::ParquetError,
1041        #[snafu(implicit)]
1042        location: Location,
1043    },
1044
1045    #[snafu(display("Partition {} out of range, {} in total", given, all))]
1046    PartitionOutOfRange {
1047        given: usize,
1048        all: usize,
1049        #[snafu(implicit)]
1050        location: Location,
1051    },
1052
1053    #[snafu(display("Failed to iter data part"))]
1054    ReadDataPart {
1055        #[snafu(implicit)]
1056        location: Location,
1057        #[snafu(source)]
1058        error: parquet::errors::ParquetError,
1059    },
1060
1061    #[snafu(display("Failed to read row group in memtable"))]
1062    DecodeArrowRowGroup {
1063        #[snafu(source)]
1064        error: ArrowError,
1065        #[snafu(implicit)]
1066        location: Location,
1067    },
1068
1069    #[snafu(display("Invalid region options, {}", reason))]
1070    InvalidRegionOptions {
1071        reason: String,
1072        #[snafu(implicit)]
1073        location: Location,
1074    },
1075
1076    #[snafu(display("checksum mismatch (actual: {}, expected: {})", actual, expected))]
1077    ChecksumMismatch { actual: u32, expected: u32 },
1078
1079    #[snafu(display(
1080        "No checkpoint found, region: {}, last_version: {}",
1081        region_id,
1082        last_version
1083    ))]
1084    NoCheckpoint {
1085        region_id: RegionId,
1086        last_version: ManifestVersion,
1087        #[snafu(implicit)]
1088        location: Location,
1089    },
1090
1091    #[snafu(display(
1092        "No manifests found in range: [{}..{}), region: {}, last_version: {}",
1093        start_version,
1094        end_version,
1095        region_id,
1096        last_version
1097    ))]
1098    NoManifests {
1099        region_id: RegionId,
1100        start_version: ManifestVersion,
1101        end_version: ManifestVersion,
1102        last_version: ManifestVersion,
1103        #[snafu(implicit)]
1104        location: Location,
1105    },
1106
1107    #[snafu(display(
1108        "Failed to install manifest to {}, region: {}, available manifest version: {}, last version: {}",
1109        target_version,
1110        region_id,
1111        available_version,
1112        last_version
1113    ))]
1114    InstallManifestTo {
1115        region_id: RegionId,
1116        target_version: ManifestVersion,
1117        available_version: ManifestVersion,
1118        #[snafu(implicit)]
1119        location: Location,
1120        last_version: ManifestVersion,
1121    },
1122
1123    #[snafu(display("Region {} is stopped", region_id))]
1124    RegionStopped {
1125        region_id: RegionId,
1126        #[snafu(implicit)]
1127        location: Location,
1128    },
1129
1130    #[snafu(display(
1131        "Time range predicate overflows, timestamp: {:?}, target unit: {}",
1132        timestamp,
1133        unit
1134    ))]
1135    TimeRangePredicateOverflow {
1136        timestamp: Timestamp,
1137        unit: TimeUnit,
1138        #[snafu(implicit)]
1139        location: Location,
1140    },
1141
1142    #[snafu(display("Failed to open region"))]
1143    OpenRegion {
1144        #[snafu(implicit)]
1145        location: Location,
1146        source: Arc<Error>,
1147    },
1148
1149    #[snafu(display(
1150        "Region {} does not satisfy requirement '{}': {}",
1151        region_id,
1152        requirement,
1153        reason
1154    ))]
1155    RegionRequirement {
1156        region_id: RegionId,
1157        requirement: &'static str,
1158        reason: &'static str,
1159        #[snafu(implicit)]
1160        location: Location,
1161    },
1162
1163    #[snafu(display("Failed to parse job id"))]
1164    ParseJobId {
1165        #[snafu(implicit)]
1166        location: Location,
1167        #[snafu(source)]
1168        error: uuid::Error,
1169    },
1170
1171    #[snafu(display("Operation is not supported: {}", err_msg))]
1172    UnsupportedOperation {
1173        err_msg: String,
1174        #[snafu(implicit)]
1175        location: Location,
1176    },
1177
1178    #[snafu(display(
1179        "Failed to remotely compact region {} by job {:?} due to {}",
1180        region_id,
1181        job_id,
1182        reason
1183    ))]
1184    RemoteCompaction {
1185        region_id: RegionId,
1186        job_id: Option<JobId>,
1187        reason: String,
1188        #[snafu(implicit)]
1189        location: Location,
1190    },
1191
1192    #[snafu(display("Failed to initialize puffin stager"))]
1193    PuffinInitStager {
1194        source: puffin::error::Error,
1195        #[snafu(implicit)]
1196        location: Location,
1197    },
1198
1199    #[snafu(display("Failed to purge puffin stager"))]
1200    PuffinPurgeStager {
1201        source: puffin::error::Error,
1202        #[snafu(implicit)]
1203        location: Location,
1204    },
1205
1206    #[snafu(display("Failed to build puffin reader"))]
1207    PuffinBuildReader {
1208        source: puffin::error::Error,
1209        #[snafu(implicit)]
1210        location: Location,
1211    },
1212
1213    #[snafu(display("Failed to retrieve index options from column metadata"))]
1214    IndexOptions {
1215        #[snafu(implicit)]
1216        location: Location,
1217        source: datatypes::error::Error,
1218        column_name: String,
1219    },
1220
1221    #[snafu(display("Failed to retrieve compression options of column {column_name}"))]
1222    CompressionOptions {
1223        #[snafu(implicit)]
1224        location: Location,
1225        source: datatypes::error::Error,
1226        column_name: String,
1227    },
1228
1229    #[snafu(display("Failed to create fulltext index creator"))]
1230    CreateFulltextCreator {
1231        source: index::fulltext_index::error::Error,
1232        #[snafu(implicit)]
1233        location: Location,
1234    },
1235
1236    #[snafu(display("Failed to cast vector of {from} to {to}"))]
1237    CastVector {
1238        #[snafu(implicit)]
1239        location: Location,
1240        from: ConcreteDataType,
1241        to: ConcreteDataType,
1242        source: datatypes::error::Error,
1243    },
1244
1245    #[snafu(display("Failed to push text to fulltext index"))]
1246    FulltextPushText {
1247        source: index::fulltext_index::error::Error,
1248        #[snafu(implicit)]
1249        location: Location,
1250    },
1251
1252    #[snafu(display("Failed to finalize fulltext index creator"))]
1253    FulltextFinish {
1254        source: index::fulltext_index::error::Error,
1255        #[snafu(implicit)]
1256        location: Location,
1257    },
1258
1259    #[snafu(display("Failed to apply fulltext index"))]
1260    ApplyFulltextIndex {
1261        source: index::fulltext_index::error::Error,
1262        #[snafu(implicit)]
1263        location: Location,
1264    },
1265
1266    #[snafu(display("SST file {} does not contain valid stats info", file_path))]
1267    StatsNotPresent {
1268        file_path: String,
1269        #[snafu(implicit)]
1270        location: Location,
1271    },
1272
1273    #[snafu(display("Failed to decode stats of file {}", file_path))]
1274    DecodeStats {
1275        file_path: String,
1276        #[snafu(implicit)]
1277        location: Location,
1278    },
1279
1280    #[snafu(display("Invalid SST primary key range: {reason}"))]
1281    InvalidPrimaryKeyRange {
1282        reason: String,
1283        #[snafu(implicit)]
1284        location: Location,
1285    },
1286
1287    #[snafu(display("Failed to decode SST primary key range {endpoint} endpoint"))]
1288    DecodePrimaryKeyRange {
1289        endpoint: &'static str,
1290        source: mito_codec::error::Error,
1291        #[snafu(implicit)]
1292        location: Location,
1293    },
1294
1295    #[snafu(display("Region {} is busy", region_id))]
1296    RegionBusy {
1297        region_id: RegionId,
1298        #[snafu(implicit)]
1299        location: Location,
1300    },
1301
1302    #[snafu(display("Failed to get schema metadata"))]
1303    GetSchemaMetadata {
1304        source: common_meta::error::Error,
1305        #[snafu(implicit)]
1306        location: Location,
1307    },
1308
1309    #[snafu(display("Timeout"))]
1310    Timeout {
1311        #[snafu(source)]
1312        error: Elapsed,
1313        #[snafu(implicit)]
1314        location: Location,
1315    },
1316
1317    #[snafu(display("Failed to read file metadata"))]
1318    Metadata {
1319        #[snafu(source)]
1320        error: std::io::Error,
1321        #[snafu(implicit)]
1322        location: Location,
1323    },
1324
1325    #[snafu(display("Failed to push value to bloom filter"))]
1326    PushBloomFilterValue {
1327        source: index::bloom_filter::error::Error,
1328        #[snafu(implicit)]
1329        location: Location,
1330    },
1331
1332    #[snafu(display("Failed to finish bloom filter"))]
1333    BloomFilterFinish {
1334        source: index::bloom_filter::error::Error,
1335        #[snafu(implicit)]
1336        location: Location,
1337    },
1338
1339    #[snafu(display("Manual compaction is override by following operations."))]
1340    ManualCompactionOverride {},
1341
1342    #[snafu(display("Manual compaction is already running for region {region_id}."))]
1343    ManualCompactionAlreadyRunning { region_id: RegionId },
1344
1345    #[snafu(display("Compaction is cancelled."))]
1346    CompactionCancelled {},
1347
1348    #[snafu(display("Flush is cancelled."))]
1349    FlushCancelled {},
1350
1351    #[snafu(display("Compaction memory exhausted for region {region_id} (policy: {policy})",))]
1352    CompactionMemoryExhausted {
1353        region_id: RegionId,
1354        policy: String,
1355        #[snafu(source)]
1356        source: common_memory_manager::Error,
1357        #[snafu(implicit)]
1358        location: Location,
1359    },
1360
1361    #[snafu(display(
1362        "Incompatible WAL provider change. This is typically caused by changing WAL provider in database config file without completely cleaning existing files. Global provider: {}, region provider: {}",
1363        global,
1364        region
1365    ))]
1366    IncompatibleWalProviderChange { global: String, region: String },
1367
1368    #[snafu(display("Expected mito manifest info"))]
1369    MitoManifestInfo {
1370        #[snafu(implicit)]
1371        location: Location,
1372    },
1373
1374    #[snafu(display("Failed to scan series"))]
1375    ScanSeries {
1376        #[snafu(implicit)]
1377        location: Location,
1378        source: Arc<Error>,
1379    },
1380
1381    #[snafu(display("Partition {} scan multiple times", partition))]
1382    ScanMultiTimes {
1383        partition: usize,
1384        #[snafu(implicit)]
1385        location: Location,
1386    },
1387
1388    #[snafu(display("Invalid partition expression: {}", expr))]
1389    InvalidPartitionExpr {
1390        expr: String,
1391        #[snafu(implicit)]
1392        location: Location,
1393        source: partition::error::Error,
1394    },
1395
1396    #[snafu(display("Failed to decode bulk wal entry"))]
1397    ConvertBulkWalEntry {
1398        #[snafu(implicit)]
1399        location: Location,
1400        source: common_grpc::Error,
1401    },
1402
1403    #[snafu(display("Failed to encode"))]
1404    Encode {
1405        #[snafu(implicit)]
1406        location: Location,
1407        source: mito_codec::error::Error,
1408    },
1409
1410    #[snafu(display("Failed to decode"))]
1411    Decode {
1412        #[snafu(implicit)]
1413        location: Location,
1414        source: mito_codec::error::Error,
1415    },
1416
1417    #[snafu(display("Unexpected: {reason}"))]
1418    Unexpected {
1419        reason: String,
1420        #[snafu(implicit)]
1421        location: Location,
1422    },
1423
1424    #[cfg(feature = "enterprise")]
1425    #[snafu(display("Failed to scan external range"))]
1426    ScanExternalRange {
1427        source: BoxedError,
1428        #[snafu(implicit)]
1429        location: Location,
1430    },
1431
1432    #[snafu(display(
1433        "Inconsistent timestamp column length, expect: {}, actual: {}",
1434        expected,
1435        actual
1436    ))]
1437    InconsistentTimestampLength {
1438        expected: usize,
1439        actual: usize,
1440        #[snafu(implicit)]
1441        location: Location,
1442    },
1443
1444    #[snafu(display(
1445        "Too many files to read concurrently: {}, max allowed: {}",
1446        actual,
1447        max
1448    ))]
1449    TooManyFilesToRead {
1450        actual: usize,
1451        max: usize,
1452        #[snafu(implicit)]
1453        location: Location,
1454    },
1455
1456    #[snafu(display("Duration out of range: {input:?}"))]
1457    DurationOutOfRange {
1458        input: std::time::Duration,
1459        #[snafu(source)]
1460        error: chrono::OutOfRangeError,
1461        #[snafu(implicit)]
1462        location: Location,
1463    },
1464
1465    #[snafu(display("GC job permit exhausted"))]
1466    TooManyGcJobs {
1467        #[snafu(implicit)]
1468        location: Location,
1469    },
1470
1471    #[snafu(display(
1472        "Staging partition expr mismatch, manifest: {:?}, request: {}",
1473        manifest_expr,
1474        request_expr
1475    ))]
1476    StagingPartitionExprMismatch {
1477        manifest_expr: Option<String>,
1478        request_expr: String,
1479        #[snafu(implicit)]
1480        location: Location,
1481    },
1482
1483    #[snafu(display(
1484        "Invalid source and target region, source: {}, target: {}",
1485        source_region_id,
1486        target_region_id
1487    ))]
1488    InvalidSourceAndTargetRegion {
1489        source_region_id: RegionId,
1490        target_region_id: RegionId,
1491        #[snafu(implicit)]
1492        location: Location,
1493    },
1494
1495    #[snafu(display("Failed to prune file"))]
1496    PruneFile {
1497        source: Arc<Error>,
1498        #[snafu(implicit)]
1499        location: Location,
1500    },
1501
1502    #[snafu(display("Failed to cast column"))]
1503    CastColumn {
1504        #[snafu(source)]
1505        error: datafusion::error::DataFusionError,
1506        #[snafu(implicit)]
1507        location: Location,
1508    },
1509
1510    #[snafu(display("Failed to generate Arrow schema from Parquet file: {}", file))]
1511    ParquetToArrowSchema {
1512        file: String,
1513        #[snafu(source)]
1514        error: parquet::errors::ParquetError,
1515        #[snafu(implicit)]
1516        location: Location,
1517    },
1518
1519    #[snafu(display(
1520        "Region {} is in {:?} state, expect: Writable, Staging or Downgrading",
1521        region_id,
1522        state
1523    ))]
1524    FlushableRegionState {
1525        region_id: RegionId,
1526        state: RegionRoleState,
1527        #[snafu(implicit)]
1528        location: Location,
1529    },
1530}
1531
1532pub type Result<T, E = Error> = std::result::Result<T, E>;
1533
1534impl Error {
1535    /// Returns true if we need to fill default value for a region.
1536    pub(crate) fn is_fill_default(&self) -> bool {
1537        matches!(self, Error::FillDefault { .. })
1538    }
1539
1540    /// Returns true if the file is not found on the object store.
1541    pub(crate) fn is_object_not_found(&self) -> bool {
1542        match self {
1543            Error::OpenDal { error, .. } => error.kind() == ErrorKind::NotFound,
1544            Error::ManifestDeltaNotFound { .. } => true,
1545            Error::LoadSstMeta { source, .. }
1546            | Error::LoadParquetPage { source, .. }
1547            | Error::LoadRangeResult { source, .. } => source.is_object_not_found(),
1548            _ => false,
1549        }
1550    }
1551
1552    /// Returns whether a failed manifest update may have been persisted.
1553    ///
1554    /// Unknown errors are treated conservatively because deleting output SSTs after an ambiguous
1555    /// manifest write could leave the manifest referencing missing files. The retry layer returns
1556    /// the last attempt's error, so an error that can follow a stored attempt (throttling, or a 403
1557    /// from a revoked key, a changed bucket policy or clock skew) never proves nothing was written.
1558    pub(crate) fn may_have_persisted_manifest_update(&self) -> bool {
1559        match self {
1560            // Applicability and capability checks reject the edit before storage I/O.
1561            Error::InvalidRequest { .. }
1562            | Error::UpdateManifest { .. }
1563            | Error::RegionState { .. }
1564            | Error::RegionTruncated { .. }
1565            | Error::RegionStopped { .. }
1566            | Error::RegionLeaseExpired { .. }
1567            | Error::SerdeJson { .. }
1568            | Error::CompressObject { .. } => false,
1569            Error::OpenDal { error, .. } => !matches!(
1570                error.kind(),
1571                ErrorKind::Unsupported
1572                    | ErrorKind::ConfigInvalid
1573                    | ErrorKind::NotFound
1574                    | ErrorKind::IsADirectory
1575                    | ErrorKind::NotADirectory
1576                    | ErrorKind::AlreadyExists
1577                    | ErrorKind::IsSameFile
1578                    | ErrorKind::ConditionNotMatch
1579                    | ErrorKind::RangeNotSatisfied
1580            ),
1581            _ => true,
1582        }
1583    }
1584}
1585
1586impl ErrorExt for Error {
1587    fn status_code(&self) -> StatusCode {
1588        use Error::*;
1589
1590        match self {
1591            #[cfg(feature = "enterprise")]
1592            RouteMultiRegion { source, .. } => source.status_code(),
1593            #[cfg(feature = "enterprise")]
1594            InvalidMultiRegionCompaction { .. } => StatusCode::InvalidArguments,
1595            #[cfg(feature = "enterprise")]
1596            MultiRegionCompactionResource { .. } => StatusCode::RuntimeResourcesExhausted,
1597            SstWriteMemoryExceeded { .. } => StatusCode::RuntimeResourcesExhausted,
1598            DataTypeMismatch { source, .. } => source.status_code(),
1599            OpenDal { .. }
1600            | ManifestDeltaNotFound { .. }
1601            | ManifestVersionConflict { .. }
1602            | ManifestCheckpointVanished { .. }
1603            | ReadParquet { .. } => StatusCode::StorageUnavailable,
1604            WriteWal { source, .. }
1605            | ReadWal { source, .. }
1606            | DeleteWal { source, .. }
1607            | WaitWalDurable { source, .. }
1608            | CheckWalHistory { source, .. } => source.status_code(),
1609            CompressObject { .. }
1610            | DecompressObject { .. }
1611            | SerdeJson { .. }
1612            | Utf8 { .. }
1613            | NewRecordBatch { .. }
1614            | RegionCorrupted { .. }
1615            | InconsistentFile { .. }
1616            | CreateDefault { .. }
1617            | InvalidParquet { .. }
1618            | OperateAbortedIndex { .. }
1619            | IndexEncodeNull { .. }
1620            | NoCheckpoint { .. }
1621            | NoManifests { .. }
1622            | FilesLost { .. }
1623            | InstallManifestTo { .. }
1624            | Unexpected { .. }
1625            | SerializeColumnMetadata { .. }
1626            | SerializeManifest { .. }
1627            | StagingPartitionExprMismatch { .. } => StatusCode::Unexpected,
1628
1629            RegionNotFound { .. } => StatusCode::RegionNotFound,
1630            ObjectStoreNotFound { .. }
1631            | InvalidScanIndex { .. }
1632            | InvalidMeta { .. }
1633            | InvalidRequest { .. }
1634            | PartitionExprVersionMismatch { .. }
1635            | FillDefault { .. }
1636            | ConvertColumnDataType { .. }
1637            | ColumnNotFound { .. }
1638            | InvalidMetadata { .. }
1639            | InvalidRegionOptions { .. }
1640            | InvalidWalReadRequest { .. }
1641            | PartitionOutOfRange { .. }
1642            | ParseJobId { .. }
1643            | DurationOutOfRange { .. }
1644            | MissingOldManifest { .. }
1645            | MissingNewManifest { .. }
1646            | MissingManifest { .. }
1647            | NoOldManifests { .. }
1648            | MissingPartitionExpr { .. }
1649            | SerializePartitionExpr { .. }
1650            | InvalidSourceAndTargetRegion { .. } => StatusCode::InvalidArguments,
1651
1652            IncrementalQueryStale { .. } | SnapshotFenceStale { .. } => StatusCode::RequestOutdated,
1653
1654            SequenceRangeUnsupported { .. } => StatusCode::Unsupported,
1655
1656            RegionSequenceDomainBroken { .. }
1657            | RegionMetadataNotFound { .. }
1658            | Join { .. }
1659            | WorkerStopped { .. }
1660            | EngineStopped { .. }
1661            | Recv { .. }
1662            | DecodeWal { .. }
1663            | ComputeArrow { .. }
1664            | EvalPartitionFilter { .. }
1665            | MergeCandidateSeries { .. }
1666            | BiErrors { .. }
1667            | StopScheduler { .. }
1668            | ComputeVector { .. }
1669            | EncodeMemtable { .. }
1670            | CreateDir { .. }
1671            | ReadDataPart { .. }
1672            | BuildEntry { .. }
1673            | Metadata { .. }
1674            | CastColumn { .. }
1675            | MitoManifestInfo { .. }
1676            | ParquetToArrowSchema { .. } => StatusCode::Internal,
1677
1678            FetchManifests { source, .. } => source.status_code(),
1679
1680            OpenRegion { source, .. } => source.status_code(),
1681
1682            WriteParquet { .. } => StatusCode::StorageUnavailable,
1683            WriteGroup { source, .. }
1684            | LoadSstMeta { source, .. }
1685            | LoadParquetPage { source, .. }
1686            | LoadRangeResult { source, .. } => source.status_code(),
1687            InvalidBatch { .. } => StatusCode::InvalidArguments,
1688            InvalidRecordBatch { .. } => StatusCode::InvalidArguments,
1689            ConvertVector { source, .. } => source.status_code(),
1690
1691            PrimaryKeyLengthMismatch { .. } => StatusCode::InvalidArguments,
1692            InvalidSender { .. } => StatusCode::InvalidArguments,
1693            InvalidSchedulerState { .. } => StatusCode::InvalidArguments,
1694            RegionRequirement { .. } => StatusCode::InvalidArguments,
1695            DeleteSsts { .. } | DeleteIndex { .. } | DeleteIndexes { .. } => {
1696                StatusCode::StorageUnavailable
1697            }
1698            FlushRegion { source, .. } | BuildIndexAsync { source, .. } => source.status_code(),
1699            IndexBuildIncomplete { .. } => StatusCode::IllegalState,
1700            RegionDropped { .. } => StatusCode::Cancelled,
1701            RegionClosed { .. } => StatusCode::Cancelled,
1702            StaleCompactionExecution { .. } => StatusCode::Cancelled,
1703            RegionTruncated { .. } => StatusCode::Cancelled,
1704            RejectWrite { .. } | RejectWriteInStaging { .. } => StatusCode::StorageUnavailable,
1705            CompactRegion { source, .. } => source.status_code(),
1706            EditRegion { source, .. } => source.status_code(),
1707            CompatReader { .. } => StatusCode::Unexpected,
1708            InvalidRegionRequest { source, .. } => source.status_code(),
1709            RegionState { .. } | UpdateManifest { .. } => StatusCode::RegionNotReady,
1710            RegionLeaseExpired { .. } | UnacknowledgedWrite { .. } => StatusCode::RegionNotReady,
1711            RegionPendingTails { .. } => StatusCode::RegionNotReady,
1712            JsonOptions { .. } => StatusCode::InvalidArguments,
1713            EmptyRegionDir { .. } | EmptyManifestDir { .. } => StatusCode::RegionNotFound,
1714            ConvertValue { source, .. } => source.status_code(),
1715            ApplyBloomFilterIndex { source, .. } => source.status_code(),
1716            InvalidPartitionExpr { source, .. } => source.status_code(),
1717            BuildIndexApplier { source, .. }
1718            | PushIndexValue { source, .. }
1719            | ApplyInvertedIndex { source, .. }
1720            | IndexFinish { source, .. } => source.status_code(),
1721            PuffinReadBlob { source, .. }
1722            | PuffinAddBlob { source, .. }
1723            | PuffinInitStager { source, .. }
1724            | PuffinBuildReader { source, .. }
1725            | PuffinPurgeStager { source, .. } => source.status_code(),
1726            CleanDir { .. } => StatusCode::Unexpected,
1727            InvalidConfig { .. } => StatusCode::InvalidArguments,
1728            StaleLogEntry { .. }
1729            | InvalidNativeHistogramSubfield { .. }
1730            | InvalidNativeHistogramFieldId { .. } => StatusCode::Unexpected,
1731
1732            External { source, .. } => source.status_code(),
1733
1734            RecordBatch { source, .. } => source.status_code(),
1735
1736            Download { .. } | Upload { .. } => StatusCode::StorageUnavailable,
1737            ChecksumMismatch { .. } => StatusCode::Unexpected,
1738            RegionStopped { .. } => StatusCode::RegionNotReady,
1739            TimeRangePredicateOverflow { .. } => StatusCode::InvalidArguments,
1740            UnsupportedOperation { .. } => StatusCode::Unsupported,
1741            RemoteCompaction { .. } => StatusCode::Unexpected,
1742
1743            IndexOptions { source, .. } => source.status_code(),
1744            CompressionOptions { source, .. } => source.status_code(),
1745            CreateFulltextCreator { source, .. } => source.status_code(),
1746            CastVector { source, .. } => source.status_code(),
1747            FulltextPushText { source, .. }
1748            | FulltextFinish { source, .. }
1749            | ApplyFulltextIndex { source, .. } => source.status_code(),
1750            DecodeStats { .. }
1751            | StatsNotPresent { .. }
1752            | InvalidPrimaryKeyRange { .. }
1753            | DecodePrimaryKeyRange { .. } => StatusCode::Internal,
1754            RegionBusy { .. } => StatusCode::RegionBusy,
1755            GetSchemaMetadata { source, .. } => source.status_code(),
1756            Timeout { .. } => StatusCode::Cancelled,
1757
1758            DecodeArrowRowGroup { .. } => StatusCode::Internal,
1759
1760            PushBloomFilterValue { source, .. } | BloomFilterFinish { source, .. } => {
1761                source.status_code()
1762            }
1763
1764            ManualCompactionOverride {} | CompactionCancelled {} | FlushCancelled {} => {
1765                StatusCode::Cancelled
1766            }
1767
1768            // A concurrent manual compaction fails fast instead of being queued;
1769            // the conflict is reported to the caller, which decides whether to
1770            // issue a new request after the running one finishes.
1771            ManualCompactionAlreadyRunning { .. } => StatusCode::RegionBusy,
1772
1773            CompactionMemoryExhausted { source, .. } => source.status_code(),
1774
1775            IncompatibleWalProviderChange { .. } => StatusCode::InvalidArguments,
1776
1777            ScanSeries { source, .. } => source.status_code(),
1778
1779            ScanMultiTimes { .. } => StatusCode::InvalidArguments,
1780            ConvertBulkWalEntry { source, .. } => source.status_code(),
1781
1782            Encode { source, .. } | Decode { source, .. } => source.status_code(),
1783
1784            #[cfg(feature = "enterprise")]
1785            ScanExternalRange { source, .. } => source.status_code(),
1786
1787            InconsistentTimestampLength { .. } => StatusCode::InvalidArguments,
1788
1789            TooManyFilesToRead { .. } | TooManyGcJobs { .. } => StatusCode::RateLimited,
1790
1791            PruneFile { source, .. } => source.status_code(),
1792
1793            FlushableRegionState { .. } => StatusCode::RegionNotReady,
1794        }
1795    }
1796
1797    fn as_any(&self) -> &dyn Any {
1798        self
1799    }
1800
1801    fn retry_hint(&self) -> RetryHint {
1802        use Error::*;
1803
1804        match self {
1805            PartitionExprVersionMismatch { .. }
1806            | RegionNotFound { .. }
1807            | RegionClosed { .. }
1808            | RejectWriteInStaging { .. }
1809            | RegionLeaseExpired { .. }
1810            | UnacknowledgedWrite { .. }
1811            | RegionState {
1812                state: RegionRoleState::Follower,
1813                ..
1814            } => RetryHint::RetryAfterRouteRefresh,
1815            ReadParquet { .. }
1816            | WriteParquet { .. }
1817            | RejectWrite { .. }
1818            | Download { .. }
1819            | Upload { .. }
1820            | RegionState { .. }
1821            | UpdateManifest { .. }
1822            | RegionStopped { .. }
1823            | RegionBusy { .. }
1824            | RegionPendingTails { .. }
1825            | ManualCompactionAlreadyRunning { .. }
1826            | FlushableRegionState { .. }
1827            | ManifestDeltaNotFound { .. }
1828            | ManifestVersionConflict { .. }
1829            | ManifestCheckpointVanished { .. } => RetryHint::Retryable,
1830
1831            OpenDal { error, .. }
1832            | DeleteSsts { error, .. }
1833            | DeleteIndex { error, .. }
1834            | DeleteIndexes { error, .. } => retry_hint_from_opendal_error(error),
1835
1836            WriteWal { source, .. }
1837            | ReadWal { source, .. }
1838            | DeleteWal { source, .. }
1839            | WaitWalDurable { source, .. }
1840            | CheckWalHistory { source, .. }
1841            | FetchManifests { source, .. }
1842            | External { source, .. } => source.retry_hint(),
1843
1844            OpenRegion { source, .. }
1845            | LoadSstMeta { source, .. }
1846            | LoadParquetPage { source, .. }
1847            | LoadRangeResult { source, .. }
1848            | WriteGroup { source, .. }
1849            | FlushRegion { source, .. }
1850            | BuildIndexAsync { source, .. }
1851            | CompactRegion { source, .. }
1852            | EditRegion { source, .. }
1853            | ScanSeries { source, .. }
1854            | PruneFile { source, .. } => source.retry_hint(),
1855
1856            DataTypeMismatch { source, .. }
1857            | ConvertVector { source, .. }
1858            | ConvertValue { source, .. }
1859            | IndexOptions { source, .. }
1860            | CompressionOptions { source, .. }
1861            | CastVector { source, .. } => source.retry_hint(),
1862
1863            BuildIndexApplier { source, .. }
1864            | PushIndexValue { source, .. }
1865            | ApplyInvertedIndex { source, .. }
1866            | IndexFinish { source, .. } => source.retry_hint(),
1867
1868            ApplyBloomFilterIndex { source, .. }
1869            | PushBloomFilterValue { source, .. }
1870            | BloomFilterFinish { source, .. } => source.retry_hint(),
1871
1872            PuffinReadBlob { source, .. }
1873            | PuffinAddBlob { source, .. }
1874            | PuffinInitStager { source, .. }
1875            | PuffinBuildReader { source, .. }
1876            | PuffinPurgeStager { source, .. } => source.retry_hint(),
1877
1878            CreateFulltextCreator { source, .. }
1879            | FulltextPushText { source, .. }
1880            | FulltextFinish { source, .. }
1881            | ApplyFulltextIndex { source, .. } => source.retry_hint(),
1882
1883            InvalidRegionRequest { source, .. } => source.retry_hint(),
1884            InvalidPartitionExpr { source, .. } => source.retry_hint(),
1885            RecordBatch { source, .. } => source.retry_hint(),
1886            GetSchemaMetadata { source, .. } => source.retry_hint(),
1887            CompactionMemoryExhausted { source, .. } => source.retry_hint(),
1888            ConvertBulkWalEntry { source, .. } => source.retry_hint(),
1889            Encode { source, .. } | Decode { source, .. } => source.retry_hint(),
1890
1891            #[cfg(feature = "enterprise")]
1892            ScanExternalRange { source, .. } => source.retry_hint(),
1893
1894            _ => RetryHint::NonRetryable,
1895        }
1896    }
1897}
1898
1899#[cfg(test)]
1900mod tests {
1901    use snafu::IntoError;
1902
1903    use super::*;
1904    use crate::region::RegionLeaderState;
1905
1906    #[test]
1907    fn test_partition_version_mismatch_retry_hint() {
1908        let error = PartitionExprVersionMismatchSnafu {
1909            region_id: RegionId::new(1, 1),
1910            request_version: 1u64,
1911            expected_version: 2u64,
1912        }
1913        .build();
1914        assert_eq!(error.status_code(), StatusCode::InvalidArguments);
1915        assert_eq!(error.retry_hint(), RetryHint::RetryAfterRouteRefresh);
1916    }
1917
1918    #[test]
1919    fn test_region_state_retry_hint() {
1920        let region_id = RegionId::new(1, 1);
1921        let writable = RegionRoleState::Leader(RegionLeaderState::Writable);
1922        let follower_error = RegionStateSnafu {
1923            region_id,
1924            state: RegionRoleState::Follower,
1925            expect: writable,
1926        }
1927        .build();
1928        assert_eq!(
1929            follower_error.retry_hint(),
1930            RetryHint::RetryAfterRouteRefresh
1931        );
1932        assert_eq!(follower_error.status_code(), StatusCode::RegionNotReady);
1933        let leader_error = RegionStateSnafu {
1934            region_id,
1935            state: writable,
1936            expect: RegionRoleState::Follower,
1937        }
1938        .build();
1939        assert_eq!(leader_error.retry_hint(), RetryHint::Retryable);
1940        for (error, status, hint) in [
1941            (
1942                RejectWriteSnafu { region_id }.build(),
1943                StatusCode::StorageUnavailable,
1944                RetryHint::Retryable,
1945            ),
1946            (
1947                RejectWriteInStagingSnafu { region_id }.build(),
1948                StatusCode::StorageUnavailable,
1949                RetryHint::RetryAfterRouteRefresh,
1950            ),
1951            (
1952                RegionNotFoundSnafu { region_id }.build(),
1953                StatusCode::RegionNotFound,
1954                RetryHint::RetryAfterRouteRefresh,
1955            ),
1956            (
1957                RegionClosedSnafu { region_id }.build(),
1958                StatusCode::Cancelled,
1959                RetryHint::RetryAfterRouteRefresh,
1960            ),
1961            (
1962                RegionDroppedSnafu { region_id }.build(),
1963                StatusCode::Cancelled,
1964                RetryHint::NonRetryable,
1965            ),
1966            (
1967                RegionTruncatedSnafu { region_id }.build(),
1968                StatusCode::Cancelled,
1969                RetryHint::NonRetryable,
1970            ),
1971        ] {
1972            assert_eq!(error.status_code(), status);
1973            assert_eq!(error.retry_hint(), hint);
1974        }
1975    }
1976
1977    #[test]
1978    fn test_shared_sst_metadata_preserves_error_semantics() {
1979        for source in [
1980            OpenDalSnafu {}
1981                .into_error(object_store::Error::new(ErrorKind::NotFound, "missing SST")),
1982            OpenDalSnafu {}.into_error(object_store::Error::new(
1983                ErrorKind::Unexpected,
1984                "read failed",
1985            )),
1986            RejectWriteSnafu {
1987                region_id: RegionId::new(1, 1),
1988            }
1989            .build(),
1990        ] {
1991            let expected_not_found = source.is_object_not_found();
1992            let expected_status = source.status_code();
1993            let expected_retry = source.retry_hint();
1994            let source = Arc::new(source);
1995            for wrapped in [
1996                LoadSstMetaSnafu.into_error(source.clone()),
1997                LoadRangeResultSnafu.into_error(source),
1998            ] {
1999                assert_eq!(expected_not_found, wrapped.is_object_not_found());
2000                assert_eq!(expected_status, wrapped.status_code());
2001                assert_eq!(expected_retry, wrapped.retry_hint());
2002            }
2003        }
2004    }
2005
2006    #[test]
2007    fn test_manifest_update_persistence() {
2008        let rejected_kinds = [
2009            ErrorKind::Unsupported,
2010            ErrorKind::ConfigInvalid,
2011            ErrorKind::NotFound,
2012            ErrorKind::IsADirectory,
2013            ErrorKind::NotADirectory,
2014            ErrorKind::AlreadyExists,
2015            ErrorKind::IsSameFile,
2016            ErrorKind::ConditionNotMatch,
2017            ErrorKind::RangeNotSatisfied,
2018        ];
2019        for kind in rejected_kinds {
2020            let error = OpenDalSnafu {}.into_error(object_store::Error::new(kind, "test"));
2021            assert!(
2022                !error.may_have_persisted_manifest_update(),
2023                "error kind {kind:?} should prove the manifest was not persisted"
2024            );
2025        }
2026
2027        // The last retry can fail with these kinds even though an earlier attempt was stored.
2028        for kind in [
2029            ErrorKind::Unexpected,
2030            ErrorKind::RateLimited,
2031            ErrorKind::PermissionDenied,
2032        ] {
2033            let error = OpenDalSnafu {}.into_error(object_store::Error::new(kind, "test"));
2034            assert!(
2035                error.may_have_persisted_manifest_update(),
2036                "error kind {kind:?} should not prove the manifest was not persisted"
2037            );
2038        }
2039
2040        let region_id = RegionId::new(1, 1);
2041        let error = RegionTruncatedSnafu { region_id }.build();
2042        assert!(!error.may_have_persisted_manifest_update());
2043        let error = InvalidRequestSnafu {
2044            region_id,
2045            reason: "manifest applicability check rejected the edit",
2046        }
2047        .build();
2048        assert!(!error.may_have_persisted_manifest_update());
2049
2050        // A commit refused before its PUT because the Leader deadline has passed.
2051        let error = RegionLeaseExpiredSnafu { region_id }.build();
2052        assert!(!error.may_have_persisted_manifest_update());
2053
2054        // This can be raised while applying an edit after its manifest file was saved.
2055        let error = RegionMetadataNotFoundSnafu {}.build();
2056        assert!(error.may_have_persisted_manifest_update());
2057
2058        let error = ManifestVersionConflictSnafu {
2059            version: 1u64,
2060            manifest_dir: "manifest/",
2061            reason: "test",
2062        }
2063        .build();
2064        assert!(error.may_have_persisted_manifest_update());
2065        assert!(error.retry_hint().is_retryable());
2066    }
2067}