This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-3523-18d8ed2c2c051de13ced656a91246a318f95ff00 in repository https://gitbox.apache.org/repos/asf/iceberg-rust.git
commit b802a7cab1a370e552ddc3f00ed946706e0ce817 Author: Danny C Jones <[email protected]> AuthorDate: Tue Oct 27 17:53:49 2026 +0000 fix(catalog/s3tables): attach S3 Tables SDK error as source in resulting Iceberg error (#3523) fix(catalog/s3tables): keep the SdkError as the source of SDK failures from_aws_sdk_error and the commit path kept only a Debug render of the SdkError, so callers could not downcast to the typed error to inspect the service error code or status. Attach the SdkError itself as the error source. --- Cargo.lock | 1 - crates/catalog/s3tables/Cargo.toml | 1 - crates/catalog/s3tables/src/catalog.rs | 46 +++++++++++++++++++++++----------- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 801e4597c..017d9b071 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3008,7 +3008,6 @@ dependencies = [ name = "iceberg-catalog-s3tables" version = "0.10.1" dependencies = [ - "anyhow", "arrow-array", "arrow-schema", "async-trait", diff --git a/crates/catalog/s3tables/Cargo.toml b/crates/catalog/s3tables/Cargo.toml index f7bfa0611..ef6f3e045 100644 --- a/crates/catalog/s3tables/Cargo.toml +++ b/crates/catalog/s3tables/Cargo.toml @@ -31,7 +31,6 @@ license = { workspace = true } repository = { workspace = true } [dependencies] -anyhow = { workspace = true } async-trait = { workspace = true } aws-config = { workspace = true } aws-sdk-s3tables = { workspace = true } diff --git a/crates/catalog/s3tables/src/catalog.rs b/crates/catalog/s3tables/src/catalog.rs index 73127bd90..254f20ae3 100644 --- a/crates/catalog/s3tables/src/catalog.rs +++ b/crates/catalog/s3tables/src/catalog.rs @@ -724,25 +724,23 @@ impl Catalog for S3TablesCatalog { .version_token(version_token) .metadata_location(staged_metadata_location_str); - let _ = builder.send().await.map_err(|e| { - let error = e.into_service_error(); - match error { - UpdateTableMetadataLocationError::ConflictException(_) => Error::new( + let _ = builder + .send() + .await + .map_err(|e| match e.as_service_error() { + Some(UpdateTableMetadataLocationError::ConflictException(_)) => Error::new( ErrorKind::CatalogCommitConflicts, format!("Commit conflicted for table: {table_ident}"), ) - .with_retryable(true), - UpdateTableMetadataLocationError::NotFoundException(_) => Error::new( + .with_retryable(true) + .with_source(e), + Some(UpdateTableMetadataLocationError::NotFoundException(_)) => Error::new( ErrorKind::TableNotFound, format!("Table {table_ident} is not found"), - ), - _ => Error::new( - ErrorKind::Unexpected, - "Operation failed for hitting aws sdk error", - ), - } - .with_source(anyhow::Error::msg(format!("aws sdk error: {error:?}"))) - })?; + ) + .with_source(e), + _ => from_aws_sdk_error(e), + })?; Ok(staged_table) } @@ -750,21 +748,39 @@ impl Catalog for S3TablesCatalog { /// Format AWS SDK error into iceberg error pub(crate) fn from_aws_sdk_error<T>(error: aws_sdk_s3tables::error::SdkError<T>) -> Error -where T: std::fmt::Debug { +where T: std::error::Error + Send + Sync + 'static { Error::new( ErrorKind::Unexpected, format!("Operation failed for hitting aws sdk error: {error:?}"), ) + .with_source(error) } #[cfg(test)] mod tests { + use std::error::Error as _; + use futures::TryStreamExt; use iceberg::spec::{NestedField, PrimitiveType, Schema, Type}; use iceberg::transaction::{ApplyTransactionAction, Transaction}; use super::*; + #[test] + fn test_from_aws_sdk_error_keeps_sdk_error_as_source() { + let err = from_aws_sdk_error( + aws_sdk_s3tables::error::SdkError::<GetTableError>::construction_failure("boom"), + ); + + assert_eq!(err.kind(), ErrorKind::Unexpected); + assert!( + err.source() + .and_then(|source| source + .downcast_ref::<aws_sdk_s3tables::error::SdkError<GetTableError>>()) + .is_some() + ); + } + async fn load_s3tables_catalog_from_env() -> Result<Option<S3TablesCatalog>> { let table_bucket_arn = match std::env::var("TABLE_BUCKET_ARN").ok() { Some(table_bucket_arn) => table_bucket_arn,
