use std::{
backtrace::{Backtrace, BacktraceStatus},
convert::Infallible,
num::ParseIntError,
str::Utf8Error,
};
use crate::schema::{DataType, StructType};
use crate::table_properties::ParseIntervalError;
use crate::Version;
#[cfg(feature = "default-engine-base")]
use crate::arrow::error::ArrowError;
#[cfg(feature = "default-engine-base")]
use crate::object_store;
pub type DeltaResult<T, E = Error> = std::result::Result<T, E>;
#[non_exhaustive]
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("{source}\n{backtrace}")]
Backtraced {
source: Box<Self>,
backtrace: Box<Backtrace>,
},
#[cfg(feature = "default-engine-base")]
#[error(transparent)]
Arrow(ArrowError),
#[error("Error writing checkpoint: {0}")]
CheckpointWrite(String),
#[error("Invalid engine data type. Could not convert to {0}")]
EngineDataType(String),
#[error("Error extracting type {0}: {1}")]
Extract(&'static str, &'static str),
#[error("Generic delta kernel error: {0}")]
Generic(String),
#[error("Generic error: {source}")]
GenericError {
source: Box<dyn std::error::Error + Send + Sync + 'static>,
},
#[error(transparent)]
IOError(std::io::Error),
#[error("Internal error {0}. This is a kernel bug, please report.")]
InternalError(String),
#[cfg(feature = "default-engine-base")]
#[error("Arrow error: {0}")]
Parquet(#[from] crate::parquet::errors::ParquetError),
#[cfg(feature = "default-engine-base")]
#[error("Error interacting with object store: {0}")]
ObjectStore(object_store::Error),
#[cfg(feature = "default-engine-base")]
#[error("Object store path error: {0}")]
ObjectStorePath(#[from] object_store::path::Error),
#[cfg(feature = "default-engine-base")]
#[error("Reqwest Error: {0}")]
Reqwest(#[from] reqwest::Error),
#[error("File not found: {0}")]
FileNotFound(String),
#[error("{0}")]
MissingColumn(String),
#[error("Invalid partition values: {0}")]
InvalidPartitionValues(String),
#[error("Expected column type: {0}")]
UnexpectedColumnType(String),
#[error("Expected is missing: {0}")]
MissingData(String),
#[error("No table version found.")]
MissingVersion,
#[error("Deletion Vector error: {0}")]
DeletionVector(String),
#[error("Selection vector is larger than data length: {0}")]
InvalidSelectionVector(String),
#[error("Invalid transaction state: {0}")]
InvalidTransactionState(String),
#[error("Invalid url: {0}")]
InvalidUrl(#[from] url::ParseError),
#[error(transparent)]
MalformedJson(serde_json::Error),
#[error("No table metadata found in delta log.")]
MissingMetadata,
#[error("No protocol found in delta log.")]
MissingProtocol,
#[error("Invalid protocol action in the delta log: {0}")]
InvalidProtocol(String),
#[error("No table metadata or protocol found in delta log.")]
MissingMetadataAndProtocol,
#[error("Failed to parse value '{0}' as '{1}'")]
ParseError(String, DataType),
#[error("Join failure: {0}")]
JoinFailure(String),
#[error("Could not convert to string from utf-8: {0}")]
Utf8Error(#[from] Utf8Error),
#[error("Could not parse int: {0}")]
ParseIntError(#[from] ParseIntError),
#[error("Invalid column mapping mode: {0}")]
InvalidColumnMappingMode(String),
#[error("Invalid table location: {0}.")]
InvalidTableLocation(String),
#[error("Invalid decimal: {0}")]
InvalidDecimal(String),
#[error("Invalid struct data: {0}")]
InvalidStructData(String),
#[error("Invalid expression evaluation: {0}")]
InvalidExpressionEvaluation(String),
#[error("Invalid log path: {0}")]
InvalidLogPath(String),
#[error("File already exists: {0}")]
FileAlreadyExists(String),
#[error("Unsupported: {0}")]
Unsupported(String),
#[error("Checksum write unsupported: {0}")]
ChecksumWriteUnsupported(String),
#[error(transparent)]
ParseIntervalError(#[from] ParseIntervalError),
#[error("Change data feed is unsupported for the table at version {0}")]
ChangeDataFeedUnsupported(Version),
#[error("Change data feed encountered incompatible schema. Expected {0}, got {1}")]
ChangeDataFeedIncompatibleSchema(String, String),
#[error("Invalid Checkpoint: {0}")]
InvalidCheckpoint(String),
#[error(transparent)]
LiteralExpressionTransformError(
#[from] crate::expressions::literal_expression_transform::Error,
),
#[error("Schema error: {0}")]
Schema(String),
#[error("Stats validation error: {0}")]
StatsValidation(String),
}
impl Error {
pub(crate) fn checkpoint_write(msg: impl ToString) -> Self {
Self::CheckpointWrite(msg.to_string())
}
pub fn generic_err(source: impl Into<Box<dyn std::error::Error + Send + Sync>>) -> Self {
Self::GenericError {
source: source.into(),
}
}
pub fn generic(msg: impl ToString) -> Self {
Self::Generic(msg.to_string())
}
pub fn file_not_found(path: impl ToString) -> Self {
Self::FileNotFound(path.to_string())
}
pub fn missing_column(name: impl ToString) -> Self {
Self::MissingColumn(name.to_string()).with_backtrace()
}
pub fn unexpected_column_type(name: impl ToString) -> Self {
Self::UnexpectedColumnType(name.to_string())
}
pub fn invalid_partition_values(msg: impl ToString) -> Self {
Self::InvalidPartitionValues(msg.to_string())
}
pub fn missing_data(name: impl ToString) -> Self {
Self::MissingData(name.to_string())
}
pub fn deletion_vector(msg: impl ToString) -> Self {
Self::DeletionVector(msg.to_string())
}
pub fn engine_data_type(msg: impl ToString) -> Self {
Self::EngineDataType(msg.to_string())
}
pub fn join_failure(msg: impl ToString) -> Self {
Self::JoinFailure(msg.to_string())
}
pub fn invalid_table_location(location: impl ToString) -> Self {
Self::InvalidTableLocation(location.to_string())
}
pub fn invalid_column_mapping_mode(mode: impl ToString) -> Self {
Self::InvalidColumnMappingMode(mode.to_string())
}
pub fn invalid_decimal(msg: impl ToString) -> Self {
Self::InvalidDecimal(msg.to_string())
}
pub fn invalid_struct_data(msg: impl ToString) -> Self {
Self::InvalidStructData(msg.to_string())
}
pub fn invalid_expression(msg: impl ToString) -> Self {
Self::InvalidExpressionEvaluation(msg.to_string())
}
pub(crate) fn invalid_log_path(msg: impl ToString) -> Self {
Self::InvalidLogPath(msg.to_string())
}
pub fn internal_error(msg: impl ToString) -> Self {
Self::InternalError(msg.to_string()).with_backtrace()
}
pub fn invalid_protocol(msg: impl ToString) -> Self {
Self::InvalidProtocol(msg.to_string())
}
pub fn invalid_transaction_state(msg: impl ToString) -> Self {
Self::InvalidTransactionState(msg.to_string())
}
pub fn unsupported(msg: impl ToString) -> Self {
Self::Unsupported(msg.to_string())
}
pub fn change_data_feed_unsupported(version: impl Into<Version>) -> Self {
Self::ChangeDataFeedUnsupported(version.into())
}
pub(crate) fn change_data_feed_incompatible_schema(
expected: &StructType,
actual: &StructType,
) -> Self {
Self::ChangeDataFeedIncompatibleSchema(format!("{expected:?}"), format!("{actual:?}"))
}
pub fn invalid_checkpoint(msg: impl ToString) -> Self {
Self::InvalidCheckpoint(msg.to_string())
}
pub fn schema(msg: impl ToString) -> Self {
Self::Schema(msg.to_string())
}
pub fn stats_validation(msg: impl ToString) -> Self {
Self::StatsValidation(msg.to_string())
}
#[must_use]
pub fn with_backtrace(self) -> Self {
let backtrace = Backtrace::capture();
match backtrace.status() {
BacktraceStatus::Captured => Self::Backtraced {
source: Box::new(self),
backtrace: Box::new(backtrace),
},
_ => self,
}
}
}
macro_rules! from_with_backtrace(
( $(($error_type: ty, $error_variant: ident)), * ) => {
$(
impl From<$error_type> for Error {
fn from(value: $error_type) -> Self {
Self::$error_variant(value).with_backtrace()
}
}
)*
};
);
from_with_backtrace!(
(serde_json::Error, MalformedJson),
(std::io::Error, IOError)
);
#[cfg(feature = "default-engine-base")]
impl From<ArrowError> for Error {
fn from(value: ArrowError) -> Self {
Self::Arrow(value).with_backtrace()
}
}
#[cfg(feature = "default-engine-base")]
impl From<object_store::Error> for Error {
fn from(value: object_store::Error) -> Self {
match value {
object_store::Error::NotFound { path, .. } => Self::file_not_found(path),
err => Self::ObjectStore(err),
}
}
}
impl From<Infallible> for Error {
fn from(value: Infallible) -> Self {
match value {}
}
}