diff --git a/crates/s3/src/client.rs b/crates/s3/src/client.rs
index 9765f0b..cd05b76 100644
--- a/crates/s3/src/client.rs
+++ b/crates/s3/src/client.rs
@@ -1736,9 +1736,11 @@ impl ObjectStore for S3Client {
.send()
.await
.map_err(|e| {
- let err_str = e.to_string();
+ let err_str = Self::format_sdk_error(&e);
if err_str.contains("NotFound") || err_str.contains("NoSuchBucket") {
Error::NotFound(format!("Bucket not found: {bucket}"))
+ } else if err_str.contains("BucketNotEmpty") {
+ Error::Conflict(err_str)
} else {
Error::Network(err_str)
}
@@ -3528,6 +3530,54 @@ mod tests {
}
}
+ #[tokio::test]
+ async fn delete_bucket_maps_bucket_not_empty_to_conflict() {
+ let response = http::Response::builder()
+ .status(409)
+ .header("x-amz-error-code", "BucketNotEmpty")
+ .body(SdkBody::from(
+ r#"
+
+ BucketNotEmpty
+ The bucket you tried to delete is not empty.
+"#,
+ ))
+ .expect("build delete bucket response");
+ let (client, _request_receiver) = test_s3_client(Some(response));
+
+ let result = client.delete_bucket("bucket").await;
+
+ match result {
+ Err(Error::Conflict(message)) => assert!(message.contains("BucketNotEmpty")),
+ other => panic!("Expected Conflict for non-empty bucket, got: {other:?}"),
+ }
+ }
+
+ #[tokio::test]
+ async fn delete_bucket_maps_missing_bucket_to_not_found() {
+ let response = http::Response::builder()
+ .status(404)
+ .header("x-amz-error-code", "NoSuchBucket")
+ .body(SdkBody::from(
+ r#"
+
+ NoSuchBucket
+ The specified bucket does not exist.
+"#,
+ ))
+ .expect("build missing bucket response");
+ let (client, _request_receiver) = test_s3_client(Some(response));
+
+ let result = client.delete_bucket("missing-bucket").await;
+
+ match result {
+ Err(Error::NotFound(message)) => {
+ assert_eq!(message, "Bucket not found: missing-bucket")
+ }
+ other => panic!("Expected NotFound for missing bucket, got: {other:?}"),
+ }
+ }
+
#[tokio::test]
async fn delete_objects_with_force_delete_sets_rustfs_header() {
let response = http::Response::builder()