deltalake_core/
errors.rs

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