This is an automated email from the ASF dual-hosted git repository.
Xuanwo pushed a commit to branch xuanwo/read-metadata-api
in repository https://gitbox.apache.org/repos/asf/opendal.git
The following commit(s) were added to refs/heads/xuanwo/read-metadata-api by
this push:
new a12d027b3 fix(object_store): fallback on range read metadata miss
a12d027b3 is described below
commit a12d027b3324cd55f52e8334dc538de3ef10e8dc
Author: Xuanwo <[email protected]>
AuthorDate: Wed May 27 19:37:03 2026 +0800
fix(object_store): fallback on range read metadata miss
---
core/services/s3/src/error.rs | 9 +++++++++
integrations/object_store/src/store.rs | 17 ++++++++++++++---
2 files changed, 23 insertions(+), 3 deletions(-)
diff --git a/core/services/s3/src/error.rs b/core/services/s3/src/error.rs
index da675c6de..137851a88 100644
--- a/core/services/s3/src/error.rs
+++ b/core/services/s3/src/error.rs
@@ -131,6 +131,7 @@ pub fn parse_s3_error_code(code: &str) ->
Option<(ErrorKind, bool)> {
| "ExceedAccountRateLimit"
| "ExceedBucketQPSLimit"
| "ExceedBucketRateLimit" => Some((ErrorKind::RateLimited, true)),
+ "InvalidRange" => Some((ErrorKind::RangeNotSatisfied, false)),
_ => None,
}
}
@@ -180,4 +181,12 @@ mod tests {
let out: S3Error = de::from_reader(bs.reader()).expect("must success");
assert_eq!(out, S3Error::default());
}
+
+ #[test]
+ fn test_parse_s3_error_code_invalid_range() {
+ assert_eq!(
+ parse_s3_error_code("InvalidRange"),
+ Some((ErrorKind::RangeNotSatisfied, false))
+ );
+ }
}
diff --git a/integrations/object_store/src/store.rs
b/integrations/object_store/src/store.rs
index fb274c954..408adbd61 100644
--- a/integrations/object_store/src/store.rs
+++ b/integrations/object_store/src/store.rs
@@ -115,6 +115,17 @@ fn format_read_range(range: Option<&GetRange>, size: u64)
-> Range<u64> {
}
}
+fn format_without_stat_error(err: opendal::Error, path: &str) ->
object_store::Error {
+ match err.kind() {
+ opendal::ErrorKind::Unsupported |
opendal::ErrorKind::RangeNotSatisfied => {
+ object_store::Error::NotSupported {
+ source: Box::new(err),
+ }
+ }
+ _ => format_object_store_error(err, path),
+ }
+}
+
/// OpendalStore implements ObjectStore trait by using opendal.
///
/// This allows users to use opendal as an object store without extra cost.
@@ -193,7 +204,7 @@ impl OpendalStore {
.reader_options(raw_location, format_reader_options(options, None))
.into_send()
.await
- .map_err(|err| format_object_store_error(err, location.as_ref()))?;
+ .map_err(|err| format_without_stat_error(err, location.as_ref()))?;
let mut stream = match options.range.as_ref() {
Some(GetRange::Bounded(range)) => {
@@ -206,13 +217,13 @@ impl OpendalStore {
Some(GetRange::Suffix(_)) => unreachable!("suffix range needs
object metadata"),
None => reader.into_bytes_stream(..).into_send().await,
}
- .map_err(|err| format_object_store_error(err, location.as_ref()))?;
+ .map_err(|err| format_without_stat_error(err, location.as_ref()))?;
let metadata = stream
.metadata()
.into_send()
.await
- .map_err(|err| format_object_store_error(err, location.as_ref()))?;
+ .map_err(|err| format_without_stat_error(err, location.as_ref()))?;
let attributes = format_object_attributes(&metadata);
let meta = format_object_meta(location.as_ref(), &metadata);
let read_range = format_read_range(options.range.as_ref(), meta.size);