rustdesk/rustdesk · error · CliprdrError
file handle not found
Error message
file handle not found
What it means
LocalFile::read_exact_at first calls load_handle() to (re)open the backing file, then expects self.handle to be Some. If after load_handle the handle is still None, it cannot satisfy the positional read and returns CliprdrError::FileError wrapping io::ErrorKind::NotFound with 'file handle not found' for the file's path.
Source
Thrown at libs/clipboard/src/platform/unix/local_file.rs:230
err: e,
})?;
let mut reader = BufReader::with_capacity(BLOCK_SIZE as usize * 2, handle);
reader.fill_buf().map_err(|e| CliprdrError::FileError {
path: self.path.to_string_lossy().to_string(),
err: e,
})?;
self.handle = Some(reader);
};
Ok(())
}
pub fn read_exact_at(&mut self, buf: &mut [u8], offset: u64) -> Result<(), CliprdrError> {
self.load_handle()?;
let Some(handle) = self.handle.as_mut() else {
return Err(CliprdrError::FileError {
path: self.path.to_string_lossy().to_string(),
err: std::io::Error::new(std::io::ErrorKind::NotFound, "file handle not found"),
});
};
let read_result = if offset != self.offset.load(Ordering::Relaxed) {
handle
.seek(std::io::SeekFrom::Start(offset))
.and_then(|_| handle.read_exact(buf))
} else {
handle.read_exact(buf)
};
if let Err(e) = read_result {
return Err(self.invalidate_handle(e));
}
let new_offset = offset + (buf.len() as u64);
self.offset.store(new_offset, Ordering::Relaxed);
// gc file handle
if new_offset >= self.size {View on GitHub (pinned to 91c9fccbb0)
Solutions
- Check the file still exists and is a regular file before starting the transfer
- Call load_handle()/open explicitly and verify it returns a handle before reading
- Retry the operation after re-creating the LocalFile for the path
- Verify the path is valid on the local side (not a stale remote descriptor)
Example fix
// before
self.load_handle()?;
// after: fail early if handle could not be established
self.load_handle()?;
if self.handle.is_none() {
return Err(CliprdrError::FileError {
path: self.path.to_string_lossy().to_string(),
err: std::io::Error::new(std::io::ErrorKind::NotFound, "file handle not found"),
});
} Defensive patterns
Strategy: validation
Validate before calling
// before transferring, verify the local file is readable
let p = std::path::Path::new(&path);
if !p.is_file() {
return Err(anyhow!("file missing before transfer: {}", path));
} Try / catch
match file.read_exact_at(&mut buf, offset) {
Ok(()) => {},
Err(CliprdrError::FileError { path, err }) if err.kind() == std::io::ErrorKind::NotFound => {
// re-create LocalFile for `path` and retry once
}
Err(e) => return Err(e.into()),
} Prevention
- Re-verify the file exists after listing and before download
- Call load_handle() explicitly and check handle presence before reads
- Avoid concurrent close/read on the same LocalFile
When it happens
Trigger: Calling read_exact_at on a LocalFile whose load_handle() succeeded but left self.handle unset — i.e. the underlying open path produced no handle, or the handle was cleared concurrently/between calls and load_handle did not re-open it.
Common situations: Reading a clipboard file that was deleted or became inaccessible between listing and download; the file being a special file that opens differently; a race where close/release runs while a read is in flight.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- file handle is not opened
- invalid file name {}
- failed to get general pasteboard
- Failed to create clipboard context: {}
- Failed to empty clipboard files for conn_id {}
AI-assisted analysis of rustdesk/rustdesk@91c9fccbb0 (2026-09-10).
Data as JSON: /api/errors/72dfd2e0a9dedd1b.
Report an issue: GitHub.