quickwit-oss/quickwit · error · StorageError
listing objects is not supported for storage
Error message
listing objects is not supported for storage `{}` What it means
The `Storage` trait's default `list` implementation returns a stream containing a single Internal error stating that listing is not supported for that storage type. Storages that cannot enumerate objects (historically e.g. certain specialized backends) inherit this default instead of overriding it.
Solutions
- Use a storage backend that implements `list` (local FS, S3-compatible, RAM) for listing-dependent operations
- If you own the storage implementation, override `fn list(&self, prefix) -> ListObjectsStream` to stream real objects
- Restructure the calling code to avoid prefix listing when the backend cannot enumerate (track object paths explicitly)
- Treat the StorageErrorKind::Internal from the default method as an unsupported-operation signal in generic code
Example fix
// before (custom storage missing list)
impl Storage for MyStorage { /* no list() */ }
// after
fn list(&self, prefix: &Path) -> ListObjectsStream {
stream::iter(self.entries.keys().filter(...).cloned().map(Ok)).boxed()
} Defensive patterns
Strategy: type-guard
Validate before calling
// probe support before bulk operations
match storage.list(&probe_prefix).try_next().await {
Err(e) if e.kind() == StorageErrorKind::Internal => fallback_to_no_listing(),
_ => proceed_with_listing(),
} Try / catch
match storage.list(&prefix).try_collect::<Vec<_>>().await {
Ok(objs) => use(objs),
Err(e) if e.kind() == StorageErrorKind::Internal => fallback_no_listing_backend(),
Err(e) => return Err(e.into()),
} Prevention
- Prefer backends with full list support (local FS, S3-compatible, RAM) for GC/bulk-delete flows
- Override the default `list` in any custom Storage implementation
- Document listing support in custom storage wrappers so callers know the limitation
- Gate listing-dependent maintenance jobs on backend capability checks
When it happens
Trigger: Calling `Storage::list` (or anything built on it: delete with prefix, garbage collection, merge listing) on a storage implementation that does not override the default `list` method.
Common situations: Using a custom or minimal Storage implementation in tests/tools that never implemented listing; invoking garbage-collection or bulk-delete flows against such a storage; writing generic code that assumes all storages support listing.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- failed to URL-decode listed object key
- listed object ` ` is not under storage prefix
- `append_records` should be called with `position_opt: None`
- bundled file range overlaps split footer
- bundled file range starts after it ends
AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08).
Data as JSON: /api/errors/b016b8f5029562c4.
Report an issue: GitHub.
Appendix: source
Thrown at quickwit/quickwit-storage/src/storage.rs:152
async fn get_all(&self, path: &Path) -> StorageResult<OwnedBytes>;
/// Deletes a file.
///
/// This method should return Ok(()) if the file did not exist.
async fn delete(&self, path: &Path) -> StorageResult<()>;
/// Deletes multiple files at once.
///
/// The implementation may call `[`Storage::delete`] in a loop if the underlying storage does
/// not support deleting objects in bulk. The request can fail partially, i.e. some objects are
/// successfully deleted while others are not.
async fn bulk_delete<'a>(&self, paths: &[&'a Path]) -> Result<(), BulkDeleteError>;
/// Lists object metadata for objects whose paths start with `prefix`.
///
/// Returned paths are relative to this storage root, like every other [`Storage`] operation.
fn list(&self, _prefix: &Path) -> ListObjectsStream {
let err = anyhow::anyhow!(
"listing objects is not supported for storage `{}`",
self.uri(),
);
let storage_error = StorageErrorKind::Internal.with_error(err);
stream::once(async move { Err(storage_error) }).boxed()
}
/// Returns whether a file exists or not.
async fn exists(&self, path: &Path) -> StorageResult<bool> {
match self.file_num_bytes(path).await {
Ok(_) => Ok(true),
Err(storage_err) if storage_err.kind() == StorageErrorKind::NotFound => Ok(false),
Err(other_storage_err) => Err(other_storage_err),
}
}
/// Returns a file size.
async fn file_num_bytes(&self, path: &Path) -> StorageResult<u64>;View on GitHub (pinned to a39730c5cd)