Skip to main content

deltalake_core/
errors.rs

1//! Exceptions for the deltalake crate
2use chrono::{DateTime, Utc};
3use object_store::Error as ObjectStoreError;
4
5use crate::kernel::Version;
6use crate::kernel::transaction::{CommitBuilderError, TransactionError};
7
8/// A result returned by delta-rs
9pub type DeltaResult<T, E = DeltaTableError> = Result<T, E>;
10
11/// Delta Table specific error
12#[allow(missing_docs)]
13#[derive(thiserror::Error, Debug)]
14pub enum DeltaTableError {
15    #[error("Kernel error: {0}")]
16    KernelError(#[from] delta_kernel::error::Error),
17
18    /// Error returned when reading the delta log object failed.
19    #[error("Failed to read delta log object: {}", .source)]
20    ObjectStore {
21        /// Storage error details when reading the delta log object failed.
22        #[from]
23        source: ObjectStoreError,
24    },
25
26    /// Error returned when parsing checkpoint parquet.
27    #[error("Failed to parse parquet: {}", .source)]
28    Parquet {
29        /// Parquet error details returned when reading the checkpoint failed.
30        #[from]
31        source: parquet::errors::ParquetError,
32    },
33
34    /// Error returned when converting the schema in Arrow format failed.
35    #[error("Failed to convert into Arrow schema: {}", .source)]
36    Arrow {
37        /// Arrow error details returned when converting the schema in Arrow format failed
38        #[from]
39        source: arrow::error::ArrowError,
40    },
41
42    /// Error returned when the log record has an invalid JSON.
43    #[error("Invalid JSON in log record, version={}, line=`{}`, err=`{}`", .version, .line, .json_err)]
44    InvalidJsonLog {
45        /// JSON error details returned when parsing the record JSON.
46        json_err: serde_json::error::Error,
47        /// invalid log entry content.
48        line: String,
49        /// corresponding table version for the log file.
50        version: Version,
51    },
52
53    /// Error returned when the log contains invalid stats JSON.
54    #[error("Invalid JSON in file stats: {}", .json_err)]
55    InvalidStatsJson {
56        /// JSON error details returned when parsing the stats JSON.
57        json_err: serde_json::error::Error,
58    },
59
60    /// Error returned when the DeltaTable has an invalid version.
61    #[error("Invalid table version: {0}")]
62    InvalidVersion(Version),
63
64    /// Error returned when an operation requests an older version than the currently loaded one.
65    #[error(
66        "Cannot downgrade from version {current_version} to {requested_version}; use DeltaTable.load_version()"
67    )]
68    VersionDowngrade {
69        /// The currently loaded version.
70        current_version: Version,
71        /// The requested older version.
72        requested_version: Version,
73    },
74
75    /// Error returned when the datetime string is invalid for a conversion.
76    #[error("Invalid datetime string: {}", .source)]
77    InvalidDateTimeString {
78        /// Parse error details returned of the datetime string parse error.
79        #[from]
80        source: chrono::ParseError,
81    },
82
83    /// Error returned when attempting to write bad data to the table
84    #[error("{message}")]
85    InvalidData {
86        /// Action error details returned of the invalid action.
87        message: String,
88    },
89
90    /// Error returned when it is not a DeltaTable.
91    #[error("Not a Delta table: {0}")]
92    NotATable(String),
93
94    /// Error returned when no schema was found in the DeltaTable.
95    #[error("No schema found, please make sure table is loaded.")]
96    NoSchema,
97
98    /// Error returned when writes are attempted with data that doesn't match the schema of the
99    /// table
100    #[error("Data does not match the schema or partitions of the table: {}", msg)]
101    SchemaMismatch {
102        /// Information about the mismatch
103        msg: String,
104    },
105
106    /// Error returned when a partition is not formatted as a Hive Partition.
107    #[error("This partition is not formatted with key=value: {}", .partition)]
108    PartitionError {
109        /// The malformed partition used.
110        partition: String,
111    },
112
113    /// Error returned when a invalid partition filter was found.
114    #[error("Invalid partition filter found: {}.", .partition_filter)]
115    InvalidPartitionFilter {
116        /// The invalid partition filter used.
117        partition_filter: String,
118    },
119
120    /// Error returned when a line from log record is invalid.
121    #[error("Failed to read line from log record")]
122    Io {
123        /// Source error details returned while reading the log record.
124        #[from]
125        source: std::io::Error,
126    },
127
128    /// Error raised while preparing a commit
129    #[error("Commit actions are unsound: {source}")]
130    CommitValidation {
131        /// The source error
132        source: CommitBuilderError,
133    },
134
135    /// Error raised while commititng transaction
136    #[error("Transaction failed: {source}")]
137    Transaction {
138        /// The source error
139        source: TransactionError,
140    },
141
142    /// Error returned when transaction is failed to be committed because given version already exists.
143    #[error("Delta transaction failed, version {0} already exists.")]
144    VersionAlreadyExists(Version),
145
146    /// Error returned when user attempts to commit actions that don't belong to the next version.
147    #[error("Delta transaction failed, version {0} does not follow {1}")]
148    VersionMismatch(Version, Version),
149
150    /// A Feature is missing to perform operation
151    #[error("Delta-rs must be build with feature '{feature}' to support loading from: {url}.")]
152    MissingFeature {
153        /// Name of the missing feature
154        feature: &'static str,
155        /// Storage location url
156        url: String,
157    },
158
159    /// A Feature is missing to perform operation
160    #[error("Cannot infer storage location from: {0}")]
161    InvalidTableLocation(String),
162
163    /// Generic Delta Table error
164    #[error("Log JSON serialization error: {json_err}")]
165    SerializeLogJson {
166        /// JSON serialization error
167        json_err: serde_json::error::Error,
168    },
169
170    /// Generic Delta Table error
171    #[error("Generic DeltaTable error: {0}")]
172    Generic(String),
173
174    /// Generic Delta Table error
175    #[error("Generic error: {source}")]
176    GenericError {
177        /// Source error
178        source: Box<dyn std::error::Error + Send + Sync + 'static>,
179    },
180
181    #[error("Kernel: {source}")]
182    Kernel {
183        #[from]
184        source: crate::kernel::Error,
185    },
186
187    #[error("Table metadata is invalid: {0}")]
188    MetadataError(String),
189
190    #[error("Table has not yet been initialized")]
191    NotInitialized,
192
193    #[error("Table has not yet been initialized with files, therefore {0} is not supported")]
194    NotInitializedWithFiles(String),
195
196    #[error("Change Data not enabled for version: {version}, Start: {start}, End: {end}")]
197    ChangeDataNotRecorded {
198        version: Version,
199        start: Version,
200        end: Version,
201    },
202
203    #[error("Reading a table version: {version} that does not have change data enabled")]
204    ChangeDataNotEnabled { version: Version },
205
206    #[error("Invalid version. Start version {start} is greater than end version {end}")]
207    ChangeDataInvalidVersionRange { start: Version, end: Version },
208
209    #[error("End timestamp {ending_timestamp} is greater than latest commit timestamp")]
210    ChangeDataTimestampGreaterThanCommit { ending_timestamp: DateTime<Utc> },
211
212    #[error("No starting version or timestamp provided for CDC")]
213    NoStartingVersionOrTimestamp,
214}
215
216impl From<object_store::path::Error> for DeltaTableError {
217    fn from(err: object_store::path::Error) -> Self {
218        Self::GenericError {
219            source: Box::new(err),
220        }
221    }
222}
223
224impl From<serde_json::Error> for DeltaTableError {
225    fn from(value: serde_json::Error) -> Self {
226        DeltaTableError::InvalidStatsJson { json_err: value }
227    }
228}
229
230impl DeltaTableError {
231    /// Crate a NotATable Error with message for given path.
232    pub fn not_a_table(path: impl AsRef<str>) -> Self {
233        let msg = format!(
234            "No snapshot or version 0 found, perhaps {} is an empty dir?",
235            path.as_ref()
236        );
237        Self::NotATable(msg)
238    }
239
240    /// Create a [Generic](DeltaTableError::Generic) error with the given message.
241    pub fn generic(msg: impl ToString) -> Self {
242        Self::Generic(msg.to_string())
243    }
244}