apache/hadoop · error · EOFException
Cannot seek after EOF
Error message
Cannot seek after EOF
What it means
DFSStripedInputStream.seek(long) validates the target exactly like the replicated stream: targetPos > getFileLength() throws EOFException('Cannot seek after EOF') (and negative targets / closed streams get their own errors just below). Because it compares against the live file length, a seek that was in-bounds against a stale cached length becomes 'after EOF' when the EC file has been truncated or is simply shorter than assumed.
Source
Thrown at hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DFSStripedInputStream.java:357
void updateReadStats(final StripedBlockUtil.BlockReadStats stats, long readTimeMS) {
if (stats == null) {
return;
}
updateReadStatistics(readStatistics, stats.getBytesRead(),
stats.isShortCircuit(), stats.getNetworkDistance());
dfsClient.updateFileSystemReadStats(stats.getNetworkDistance(),
stats.getBytesRead(), readTimeMS);
assert readStatistics.getBlockType() == BlockType.STRIPED;
dfsClient.updateFileSystemECReadStats(stats.getBytesRead());
}
/**
* Seek to a new arbitrary location.
*/
@Override
public synchronized void seek(long targetPos) throws IOException {
if (targetPos > getFileLength()) {
throw new EOFException("Cannot seek after EOF");
}
if (targetPos < 0) {
throw new EOFException("Cannot seek to negative offset");
}
if (closed.get()) {
throw new IOException("Stream is closed!");
}
if (targetPos <= blockEnd) {
final long targetOffsetInBlk = getOffsetInBlockGroup(targetPos);
if (curStripeRange.include(targetOffsetInBlk)) {
int bufOffset = getStripedBufOffset(targetOffsetInBlk);
curStripeBuf.position(bufOffset);
pos = targetPos;
return;
}
}
pos = targetPos;
blockEnd = -1;View on GitHub (pinned to 2add963021)
Solutions
- Validate against a fresh length before seeking: long len = fs.getFileStatus(path).getLen(); if (targetPos > len) handle/throw your own error.
- If file lengths can change concurrently, make rewrites atomic (write temp, rename) so readers never see shrinking files, and re-stat on any EOF/seek failure.
- Clamp in defensive code: in.seek(Math.min(targetPos, len)) when the tail is optional.
- When seeking to a footer, first check len >= footerSize and surface a clear 'file too small' error.
Example fix
// before in.seek(cachedFileLen - trailerSize); // EOFException when file shrank // after long len = fs.getFileStatus(path).getLen(); if (len < trailerSize) throw new IllegalStateException(path + " too small"); in.seek(len - trailerSize);
Defensive patterns
Strategy: validation
Validate before calling
long fileLen = fs.getFileStatus(path).getLen(); // do not trust a cached length
if (targetPos < 0 || targetPos > fileLen) {
throw new IllegalArgumentException(
"seek target " + targetPos + " outside [0, " + fileLen + "] for " + path);
}
stripedIn.seek(targetPos); Try / catch
try {
stripedIn.seek(targetPos);
} catch (EOFException e) {
long freshLen = fs.getFileStatus(path).getLen();
if (targetPos > freshLen) throw new IllegalStateException(
"file shrank under reader: wanted " + targetPos + ", len " + freshLen, e);
throw e; // transient inconsistency - re-stat and retry once
} Prevention
- Always bound seek targets by a freshly stated file length.
- Re-stat on any EOFException from seek - the file may have been truncated concurrently.
- Write temp-then-rename for rewrites so EC file lengths never move backwards for readers.
- Check len >= footerSize before seeking to footer offsets.
When it happens
Trigger: Calling seek(n) on a striped/erasure-coded file where n exceeds the file length - e.g. seek(cachedLen) after the file was rewritten shorter; seeking to footer offsets computed from stale metadata; seeking past EOF instead of checking remaining length first.
Common situations: Readers over EC-enabled warehouse paths whose files are compacted/truncated under them; index files rebuilt smaller than the cached offset table expects; porting code from replicated files where the same bug threw a different exception that happened to be caught.
Related errors
- Attempted to read past end of file
- Cannot seek after EOF
- Cannot seek to negative offset
- Stream is closed!
- BlockReader failed to seek to {}. Instead, it seeked to {}.
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/c0f49654492529d6.
Report an issue: GitHub.