tursodatabase/turso · error · std::io::Error
UnexpectedEof
UnexpectedEof
Error message
Reading past the EOF point
What it means
Windows IOCP driver: a completed read that ended with ERROR_HANDLE_EOF is translated to UnexpectedEof ("Reading past the EOF point") - the async read asked for bytes beyond the file's end, so the OS completed it with fewer or zero bytes.
Source
Thrown at core/io/win_iocp.rs:657
get_unique_key_from_completion(&completion).addr()
);
completion.complete(
bytes_received
.try_into()
.map_err(|_| GetIOCPPacketError::InvalidIO)?,
);
}
(FALSE, ERROR_OPERATION_ABORTED) => {
trace!(
"completion {} cancelled",
get_unique_key_from_completion(&completion).addr()
);
completion.abort();
}
(FALSE, error_code) => {
let error = match error_code {
ERROR_HANDLE_EOF => {
io::Error::new(io::ErrorKind::UnexpectedEof, "Reading past the EOF point")
}
code => io::Error::from_raw_os_error(
code.try_into().map_err(|_| GetIOCPPacketError::InvalidIO)?,
),
};
trace!(
"completion {} errored {error}",
get_unique_key_from_completion(&completion).addr()
);
completion.error(CompletionError::IOError(
error.kind(),
"io-error-completion",
));
}
(_, _) => unreachable!(),
}View on GitHub (pinned to 244cde92a7)
Solutions
- Verify no external tool truncates or locks the db and WAL files (add AV exclusions)
- Re-check the file size immediately before issuing reads sized from earlier metadata
- If a header/size mismatch persists, restore from backup or re-create the database
- Handle UnexpectedEof on Windows reads as a truncation signal: reopen and recover instead of retrying blindly
Example fix
// before
io.read_exact_at(buf, off).await; // sized from stale metadata
// after
let len = io.size().await;
if off + buf.len() > len {
return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "range beyond file"));
}
io.read_exact_at(buf, off).await; Defensive patterns
Strategy: validation
Validate before calling
let file_len = std::fs::metadata(&path)?.len() as usize;
if range.end > file_len {
return Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "range beyond current file size"));
} Try / catch
match io.read(...) { Err(ref e) if e.kind() == std::io::ErrorKind::UnexpectedEof => recover_or_reopen(), r => r } Prevention
- Re-check file size immediately before large reads
- Exclude database files from AV/backup interference on Windows
- Treat UnexpectedEof on Windows reads as truncation, not a transient error
When it happens
Trigger: A Windows read issued with a length computed from stale file size: the file was truncated concurrently by another process, the WAL shrank between the size check and the read, or the db header claims more pages than the file holds.
Common situations: Another process (backup, AV, editor) truncates or locks the database or WAL mid-run; a crash left the header size inconsistent with the file; or a read past the last page.
Related errors
- UnexpectedEof
- InvalidData
- failed to find static SQLite with vcpkg: {error}; the `sqlit
- Failed to read manual page: {}
- Manual page not found: {page_name}
AI-assisted analysis of tursodatabase/turso@244cde92a7 (2026-08-20).
Data as JSON: /api/errors/6583703769ed1ede.
Report an issue: GitHub.