quickwit-oss/tantivy · warning · io::Error
Unsupported
Unsupported
Error message
Async read is not supported.
What it means
FileSlice's default read_bytes_async trait method is a stub that always returns io::Error(Unsupported, "Async read is not supported."). Only backends that explicitly override read_bytes_async support async reads; the default (blocking, e.g. mmap-backed) implementation does not. This is a capability signal, not corruption.
Source
Thrown at common/src/file_slice.rs:30
/// Objects that represents files sections in tantivy.
///
/// By contract, whatever happens to the directory file, as long as a FileHandle
/// is alive, the data associated with it cannot be altered or destroyed.
///
/// The underlying behavior is therefore specific to the `Directory` that
/// created it. Despite its name, a [`FileSlice`] may or may not directly map to an actual file
/// on the filesystem.
#[async_trait]
pub trait FileHandle: 'static + Send + Sync + HasLen + fmt::Debug {
/// Reads a slice of bytes.
///
/// This method may panic if the range requested is invalid.
fn read_bytes(&self, range: Range<usize>) -> io::Result<OwnedBytes>;
#[doc(hidden)]
async fn read_bytes_async(&self, _byte_range: Range<usize>) -> io::Result<OwnedBytes> {
Err(io::Error::new(
io::ErrorKind::Unsupported,
"Async read is not supported.",
))
}
}
#[derive(Debug)]
/// A File with it's length included.
pub struct WrapFile {
file: File,
len: usize,
}
impl WrapFile {
/// Creates a new WrapFile and stores its length.
pub fn new(file: File) -> io::Result<Self> {
let len = file.metadata()?.len() as usize;
Ok(WrapFile { file, len })
}View on GitHub (pinned to b5d8deb80c)
Solutions
- Use a FileSlice implementation that overrides read_bytes_async (e.g. an async-fs-backed wrapper)
- Fall back to the blocking read_bytes when Unsupported is returned
- Open the slice synchronously and wrap it in an in-memory OwnedBytes for async contexts
- Implement read_bytes_async in your custom FileSlice impl
Example fix
// before
let bytes = file_slice.read_bytes_async(range).await?;
// after
let bytes = match file_slice.read_bytes_async(range).await {
Err(e) if e.kind() == io::ErrorKind::Unsupported => file_slice.read_bytes(range)?,
other => other?,
}; Defensive patterns
Strategy: fallback
Try / catch
let bytes = match slice.read_bytes_async(range).await {
Ok(b) => Ok(b),
Err(e) if e.kind() == io::ErrorKind::Unsupported =>
tokio::task::block_in_place(|| slice.read_bytes(range)),
Err(e) => Err(e),
}?; Prevention
- Check whether the FileSlice backend advertises async support before using async APIs
- Prefer async-capable slice implementations (async-fs/object-store backed) in async code
- Implement read_bytes_async in custom FileSlice impls
- Route blocking slices through spawn_blocking/block_in_place
When it happens
Trigger: Awaiting read_bytes_async (e.g. via async search/segment open paths) on a FileSlice implementation that didn't override the async method — typically a std::fs or mmap-backed slice, or a custom impl using the default method.
Common situations: Using async index-opening APIs on files opened with blocking File/mmap; mixing sync FileSlice with async executors; custom FileSlice impls that only implemented the sync read_bytes.
Related errors
AI-assisted analysis of quickwit-oss/tantivy@b5d8deb80c (2026-09-05).
Data as JSON: /api/errors/8df771be2ca1e52a.
Report an issue: GitHub.