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

  1. Query the actual file length (e.g. via metadata/size call) and clamp the requested length to `len - offset` before issuing the exact read.
  2. Handle the UnexpectedEof error and fall back to a non-exact read if a short read is acceptable for your use case.
  3. 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

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


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)