ClementTsang/bottom · error · anyhow::Error
Error while iterating over volumes
Error message
Error while iterating over volumes: {err:?} What it means
While walking volumes with FindNextVolumeW in all_volume_io, the last OS error was neither success nor ERROR_NO_MORE_FILES, so the library closes the find handle and bails with the iteration error. ERROR_NO_MORE_FILES is the normal loop-exit condition; any other code means enumeration genuinely failed midway. Results gathered so far are discarded.
Solutions
- Inspect the wrapped err's Win32 code; ERROR_MORE_DATA means the path buffer (MAX_PATH u16s) is too small — use a larger buffer
- Retry the full enumeration; transient races from volumes appearing/disappearing resolve on a second pass
- Return the partially collected results with a warning instead of bailing
- Check disk/storage health — persistent non-NO_MORE_FILES codes can indicate mount manager corruption (chkdsk / mountvol checks)
Example fix
// before
match err.raw_os_error() {
Some(ERROR_NO_MORE_FILES) => {}
_ => {
close_find_handle(handle)?;
bail!("Error while iterating over volumes: {err:?}");
}
}
// after
match err.raw_os_error() {
Some(ERROR_NO_MORE_FILES) => {}
_ => {
let _ = close_find_handle(handle);
eprintln!("partial volume enumeration: {err:?}"); // keep partial results
}
} Defensive patterns
Strategy: retry
Validate before calling
// use a buffer larger than MAX_PATH to survive long volume GUID paths let mut buffer = [0u16; 128]; // > MAX_PATH (260 bytes / 50 chars GUID path is fine, but be generous)
Try / catch
match all_volume_io() {
Ok(r) => r,
Err(e) => {
log::warn!("volume iteration failed, retrying once: {e:?}");
all_volume_io().unwrap_or_default()
}
} Prevention
- Allocate a generous buffer for volume GUID paths instead of bare MAX_PATH
- Avoid adding/removing drives during a scan
- Treat enumeration errors as transient and retry once
When it happens
Trigger: FindNextVolumeW stops succeeding and last_os_error is not ERROR_NO_MORE_FILES — e.g. ERROR_MORE_DATA if a volume path exceeds MAX_PATH, handle invalidated mid-iteration, or the mount point database changed while iterating (volume added/removed).
Common situations: Systems with very long volume GUID paths exceeding the MAX_PATH buffer; hot-plugging or unmounting drives during a scan; corrupted mount manager state mid-enumeration.
Related errors
- Could not get volume name for mount point
- Invalid handle value
- Handle error
- Device I/O error
- process may have already been terminated.
AI-assisted analysis of ClementTsang/bottom@b77d317502 (2026-09-07).
Data as JSON: /api/errors/ba41d844b38820a6.
Report an issue: GitHub.
Appendix: source
Thrown at src/collection/disks/windows/bindings.rs:143
let volume = current_volume(&buffer);
ret.push(volume_io(&volume).map(|res| (res, volume.to_string_lossy().to_string())));
}
// Now iterate until there are no more volumes.
while unsafe { FindNextVolumeW(handle, &mut buffer) }.is_ok() {
let volume = current_volume(&buffer);
ret.push(volume_io(&volume).map(|res| (res, volume.to_string_lossy().to_string())));
}
let err = io::Error::last_os_error();
match err.raw_os_error() {
Some(ERROR_NO_MORE_FILES) => {
// Iteration completed successfully, continue on.
}
_ => {
// Some error occurred.
close_find_handle(handle)?;
bail!("Error while iterating over volumes: {err:?}");
}
}
close_find_handle(handle)?;
Ok(ret)
}
/// Returns the volume name from a mount name if possible.
pub(crate) fn volume_name_from_mount(mount: &str) -> anyhow::Result<String> {
// According to winapi docs 50 is a reasonable length to accommodate the
// volume path https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getvolumenameforvolumemountpointw
const VOLUME_MAX_LEN: usize = 50;
let mount = {
let mount_path = Path::new(mount);
let mut wide_path = mount_path.as_os_str().encode_wide().collect::<Vec<_>>();
View on GitHub (pinned to b77d317502)