ClementTsang/bottom · error · anyhow::Error
Device I/O error
Error message
Device I/O error: {err:?} What it means
The DeviceIoControl call with IOCTL_DISK_PERFORMANCE failed inside volume_io, so the DISK_PERFORMANCE counters could not be read from the volume. The handle was successfully opened and closed; only the control-code query failed. This means the OS refused or could not service the disk-performance request for that volume.
Solutions
- Enable disk performance counters by running 'diskperf -n' (as Administrator) and retry
- Check the wrapped err for the Win32 code — ERROR_INVALID_FUNCTION (1) means the IOCTL/volume combination is unsupported
- Skip volumes that do not support the IOCTL and aggregate only the ones that do
- Verify the volume is a physical/local disk, not a mapped network or virtual volume
Example fix
// before
if let Err(err) = ret {
bail!("Device I/O error: {err:?}");
}
// after
if let Err(err) = ret {
if err.code() == HRESULT::from_win32(ERROR_INVALID_FUNCTION) {
return Ok(DISK_PERFORMANCE::default()); // counters unsupported/disabled
}
bail!("Device I/O error: {err:?}");
} Defensive patterns
Strategy: fallback
Validate before calling
// enable counters beforehand (requires admin): // run `diskperf -n` once on the target machine
Try / catch
match volume_io(&volume) {
Ok(stats) => Some(stats),
Err(e) if e.to_string().contains("Device I/O error") => None, // unsupported
Err(e) => return Err(e),
} Prevention
- Enable disk performance counters with `diskperf -n` on machines you monitor
- Expect IOCTL_DISK_PERFORMANCE to be unsupported on network/virtual volumes
- Model disk stats as Option rather than assuming every volume reports them
When it happens
Trigger: DeviceIoControl returns Err — most commonly ERROR_INVALID_FUNCTION because disk performance counters are disabled on the system, or the output buffer/size was rejected, or the volume does not support the IOCTL.
Common situations: Windows systems where 'diskperf -n' was never enabled (counters off by default on some configs/skylines); virtualized or network volumes that do not implement IOCTL_DISK_PERFORMANCE; collecting stats on dynamic/foreign disks.
Related errors
- Invalid handle value
- Handle error
- Error while iterating over volumes
- Could not get volume name for mount point
- process may have already been terminated.
AI-assisted analysis of ClementTsang/bottom@b77d317502 (2026-09-07).
Data as JSON: /api/errors/a89c2cc6c3db4514.
Report an issue: GitHub.
Appendix: source
Thrown at src/collection/disks/windows/bindings.rs:87
h_device,
IOCTL_DISK_PERFORMANCE,
None,
0,
Some(&mut disk_performance as *mut _ as _),
mem::size_of::<DISK_PERFORMANCE>() as u32,
Some(&mut bytes_returned),
None,
)
};
// SAFETY: This should be safe, we will check the result as well.
let handle_result = unsafe { CloseHandle(h_device) };
if let Err(err) = handle_result {
bail!("Handle error: {err:?}");
}
if let Err(err) = ret {
bail!("Device I/O error: {err:?}");
} else {
Ok(disk_performance)
}
}
fn current_volume(buffer: &[u16]) -> PathBuf {
let first_null = buffer.iter().position(|byte| *byte == 0x00).unwrap_or(0);
let path_string = OsString::from_wide(&buffer[..first_null]);
PathBuf::from(path_string)
}
fn close_find_handle(handle: HANDLE) -> anyhow::Result<()> {
// Clean up the handle.
// SAFETY: This should be safe, we will check the result as well.
let res = unsafe { FindVolumeClose(handle) };
Ok(res?)
}View on GitHub (pinned to b77d317502)