EpicGames/lore · error · io::Error
file ended before the requested read length
Error message
file ended before the requested read length
What it means
`IoFile::read_exact_vectored_at` loops issuing vectored reads until the requested total length has been read. If the driver's `read_vectored_at_raw` returns 0 bytes read, the file has hit EOF before the full request was satisfied, and the method fails with UnexpectedEof rather than returning a short read.
Solutions
- Query the actual file length (e.g. via metadata/size call) and clamp the requested length to `len - offset` before issuing the exact read.
- Handle the UnexpectedEof error and fall back to a non-exact read if a short read is acceptable for your use case.
- Re-read the file after the writer finishes / verify file completeness (checksums, done-marker files) before exact reads.
Example fix
// before
let n = header_len + body_len;
file.read_exact_vectored_at(buffers, offset).await?; // EOF on truncated file
// after
let file_len = file.len().await?;
let want: usize = buffers.iter().map(|b| b.len()).sum();
if offset as usize + want > file_len {
// handle truncated file or shrink the request
} Defensive patterns
Strategy: validation
Validate before calling
// Rust: verify the file is long enough before an exact vectored read
async fn can_read_exact(file: &lore_io::IoFile, want: usize, offset: u64) -> bool {
(offset as usize).saturating_add(want) <= file.len().await.unwrap_or(0)
} Try / catch
// Rust
match file.read_exact_vectored_at(buffers, offset).await {
Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => {
// truncated/incomplete file: read available bytes or wait for writer
}
r => r?,
} Prevention
- Never trust a cached file length; re-stat before large exact reads.
- Only read fixed-size structures from files known to be complete (done markers, checksums).
- Avoid exact reads against files concurrently being appended to or truncated.
When it happens
Trigger: Calling `read_exact_vectored_at` (or the exact-read wrappers over it) with a total requested length larger than the bytes remaining at `offset` — e.g. reading past the end of a truncated file, using a stale cached file size, or a concurrent writer shrinking/truncating the file mid-read.
Common situations: Reading a header/footer of fixed size from a file that was written by an older version with a smaller layout; a partially-written file from a crashed producer; race between a stat of the length and the read while another process truncates the file.
Related errors
- bytes exceeds the byte whole-file limit; open the file and…
- file refused further writes
- file ended before the requested read length
- file ended before the requested read length
- file ended before the requested read length
AI-assisted analysis of EpicGames/lore@074eb0b0d1 (2026-09-13).
Data as JSON: /api/errors/f6ce11b573194465.
Report an issue: GitHub.
Appendix: source
Thrown at lore-io/src/file.rs:213
pub async fn read_exact_vectored_at<B: StableBufListMut>(
&self,
buffers: B,
offset: u64,
) -> std::io::Result<B> {
let mut buffers = buffers;
let total: usize = buffers
.byte_segments_mut()
.map(|segment| segment.len())
.sum();
let mut done = 0;
while done < total {
let (returned, read) = self
.driver
.read_vectored_at_raw(Arc::clone(&self.file), buffers, done, offset + done as u64)
.await?;
buffers = returned;
if read == 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"file ended before the requested read length",
));
}
done += read;
}
Ok(buffers)
}
/// Writes the combined contents of all segments at `offset`, gathering
/// directly from the segments with no intermediate buffer.
pub async fn write_all_vectored_at<B: StableBufList>(
&self,
buffers: B,
offset: u64,
) -> std::io::Result<B> {
let mut buffers = buffers;
let total: usize = buffers.byte_segments().map(|segment| segment.len()).sum();View on GitHub (pinned to 074eb0b0d1)