apache/iceberg · error · EOFException
Cannot seek to position after end of file
Error message
Cannot seek to position after end of file: %s
What it means
MultiBufferInputStream backs a single stream view over a list of ByteBuffers and tracks the logical file length. seek(newPosition) beyond that length throws EOFException because the stream has no data there. It is a guard against reads past the logical end of the wrapped buffers.
Solutions
- Validate the target position against the stream length before seeking (position <= length)
- Load the correct/full buffer range that contains the offset being seeked to
- If slicing a file, seek with offsets relative to the slice, not the original file
- Refresh metadata offsets if the file was rewritten
- Catch EOFException and surface a clear 'offset beyond data' error to the caller
Example fix
// before
stream.seek(footerOffset); // EOFException when footerOffset > loaded buffers
// after
if (footerOffset > stream.getLength()) {
throw new IOException("Offset beyond stream end: " + footerOffset);
}
stream.seek(footerOffset); Defensive patterns
Strategy: validation
Validate before calling
if (newPosition > stream.getLength()) {
throw new IOException("Seek position " + newPosition + " beyond stream length " + stream.getLength());
}
stream.seek(newPosition); Try / catch
try {
stream.seek(pos);
} catch (EOFException e) {
throw new IOException("Seek beyond end of loaded data at " + pos, e);
} Prevention
- Compute seek offsets relative to the loaded buffer slice, not the original file
- Keep metadata offsets in sync with the actual byte range loaded
- Never share one MultiBufferInputStream across independent readers
When it happens
Trigger: Calling seek(long) on a MultiBufferInputStream with a position greater than the total length of the supplied buffers — typically a metadata-driven seek (footer offset, row-group offset) that exceeds the data actually loaded, or passing a stale/incorrect offset.
Common situations: Parquet column readers seeking to a row-group offset from metadata that doesn't match the buffer slice loaded; loading only a partial file range (e.g. a split) but seeking with absolute file offsets; corrupted/stale footer offsets.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Cannot seek to position after end of file
- Invalid position
- Invalid position: > stream length
- Invalid sync at
- Not enough bytes to skip
AI-assisted analysis of apache/iceberg@86d9c8fc54 (2026-09-12).
Data as JSON: /api/errors/e0a45d2dddca18cc.
Report an issue: GitHub.
Appendix: source
Thrown at core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java:72
initFromBuffers();
}
private void initFromBuffers() {
discardMark();
this.position = 0;
this.iterator = buffers.stream().map(ByteBuffer::duplicate).iterator();
nextBuffer();
}
@Override
public long getPos() {
return position;
}
@Override
public void seek(long newPosition) throws IOException {
if (newPosition > length) {
throw new EOFException(
String.format("Cannot seek to position after end of file: %s", newPosition));
}
if (position > newPosition) {
// backward seek requires returning to the initial state
initFromBuffers();
}
long bytesToSkip = newPosition - position;
skipFully(bytesToSkip);
}
@Override
public long skip(long n) {
if (n <= 0) {
return 0;
}
View on GitHub (pinned to 86d9c8fc54)