apache/hadoop · error · IOException

Cannot seek after EOF

Error message

Cannot seek after EOF

What it means

ChecksumFs's ChecksumFSInputChecker.seek(long) checks the requested position against the data file's length and throws a plain IOException ('Cannot seek after EOF') when pos exceeds it. This mirrors java.io.RandomAccessFile.seek semantics the checker adds because the underlying buffered reader cannot represent a position past the end. The length is fetched via getFileStatus, so a stale cached length is not the issue - the pos really is beyond the file.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ChecksumFs.java:316

      return super.skip(n);
    }
    
    /**
     * Seek to the given position in the stream.
     * The next read() will be from that position.
     * 
     * <p>This method does not allow seek past the end of the file.
     * This produces IOException.
     *
     * @param      pos   the postion to seek to.
     * @exception  IOException  if an I/O error occurs or seeks after EOF
     *             ChecksumException if the chunk to seek to is corrupted
     */

    @Override
    public synchronized void seek(long pos) throws IOException { 
      if (pos>getFileLength()) {
        throw new IOException("Cannot seek after EOF");
      }
      super.seek(pos);
    }

  }

  @Override
  public boolean truncate(Path f, long newLength) throws IOException {
    throw new UnsupportedOperationException("Truncate is not supported "
        + "by ChecksumFs");
  }

  /**
   * Opens an FSDataInputStream at the indicated Path.
   * @param f the file name to open
   * @param bufferSize the size of the buffer to be used.
   */
  @Override

View on GitHub (pinned to 2add963021)

Solutions

  1. Clamp before seeking: long pos = Math.min(requested, in.available() positions) - practically, fetch fs.getFileStatus(f).getLen() once and Math.min(pos, len) it.
  2. Fix the offset arithmetic: seek(end) is legal (pos == length is allowed, pos > length is not); check off-by-one where end = start + length instead of start + length - 1 style bugs.
  3. If the file was expected to be bigger, re-stat it - it may have been truncated/rewritten by another process since the length was cached.

Example fix

// before
long pos = header.startOffset() + header.size(); // may exceed file
in.seek(pos); // IOException: Cannot seek after EOF

// after
long len = in.getPos() >= 0 ? fileStatus.getLen() : 0;
in.seek(Math.min(pos, fileStatus.getLen()));
Defensive patterns

Strategy: validation

Validate before calling

long len = fc.getFileStatus(path).getLen();
if (pos > len) {
  pos = len; // clamp instead of seek-after-EOF
}

Try / catch

try {
  in.seek(pos);
} catch (IOException e) { // 'Cannot seek after EOF'
  // clamp pos to in.available()/file length and re-seek
}

Prevention

When it happens

Trigger: Calling FSDataInputStream.seek(pos) on a stream opened from a checksummed local fs (FileContext.open on file://, ChecksumFs) where pos > file length: reading a fixed-size record at an offset computed from a larger/older version of the file, seeking to end-of-file plus one, or integer math (e.g., length() vs getPos() confusion) producing an out-of-range value.

Common situations: Record readers that compute splits/offsets from a stale FileStatus after the file was truncated or replaced; unit tests seeking to fileLen exactly works but len+1 fails; code mixing 0-based and 1-based end offsets.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/0c5bda4eab8c9a7c. Report an issue: GitHub.