ClementTsang/bottom · error · anyhow::Error
Handle error
Error message
Handle error: {err:?} What it means
volume_io calls CloseHandle(h_device) after the DeviceIoControl query and bails if the close itself fails. A failing CloseHandle on a volume handle means the kernel refused to release the handle (the error is carried from the windows crate's Err variant). The disk performance data is discarded even though it was likely retrieved successfully.
Solutions
- Retry the volume_io call; this is usually a transient handle-state race
- Avoid calling disk I/O collection concurrently for the same volume from multiple threads
- Check for third-party storage filter drivers (antivirus/encryption) interfering with device handles
- Log and continue: the performance data was valid, so the close failure is rarely fatal to the caller
Defensive patterns
Strategy: retry
Try / catch
// close failure is usually transient — retry the query once
match volume_io(&volume) {
Ok(stats) => stats,
Err(e) if e.to_string().contains("Handle error") => volume_io(&volume)
.unwrap_or_else(|e2| { log::debug!("{e2:?}"); Default::default() }),
Err(e) => { log::debug!("{e:?}"); Default::default() }
} Prevention
- Avoid concurrent disk-I/O collection on the same volume
- Retry transient handle errors once before surfacing
- Watch for storage filter drivers that interfere with device handles
When it happens
Trigger: CloseHandle returns Err — e.g. the handle was already invalidated/closed, an ERROR_INVALID_HANDLE from kernel-state races, or handle-table corruption under heavy concurrent volume queries.
Common situations: Monitoring daemons querying many volumes in tight loops with multiple threads touching the same volume handle table; rare kernel races on systems under extreme load; misbehaving filter drivers interfering with device handles.
Related errors
- Invalid handle value
- Device I/O error
- Error while iterating over volumes
- Could not get volume name for mount point
- Failed to open process with PID
AI-assisted analysis of ClementTsang/bottom@b77d317502 (2026-09-07).
Data as JSON: /api/errors/21ac4b33db9eb733.
Report an issue: GitHub.
Appendix: source
Thrown at src/collection/disks/windows/bindings.rs:83
// SAFETY: This should be safe, we'll manually check the results and the
// arguments should be valid.
let ret = unsafe {
DeviceIoControl(
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.View on GitHub (pinned to b77d317502)