apache/hadoop · error · EOFException

Cannot seek after EOF

Error message

Cannot seek after EOF

What it means

seek() validates the target against the stream's current file length: targetPos > getFileLength() throws EOFException (a sibling guard rejects negative targets, and a closed stream throws 'Stream is closed!'). It fires when the caller seeks to a position computed from a stale, larger length - typically after the file was truncated or when tail logic extrapolates past EOF.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DFSInputStream.java:1642

    if (n > 0) {
      long curPos = getPos();
      long fileLen = getFileLength();
      if (n+curPos > fileLen) {
        n = fileLen - curPos;
      }
      seek(curPos+n);
      return n;
    }
    return n < 0 ? -1 : 0;
  }

  /**
   * 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!");
    }
    boolean done = false;
    if (pos <= targetPos && targetPos <= blockEnd) {
      //
      // If this seek is to a positive position in the current
      // block, and this piece of data might already be lying in
      // the TCP buffer, then just eat up the intervening data.
      //
      int diff = (int)(targetPos - pos);
      if (diff <= blockReader.available()) {
        try {
          pos += blockReader.skip(diff);

View on GitHub (pinned to 2add963021)

Solutions

  1. Clamp the target to the freshly fetched file length before seeking
  2. Re-stat the file (and re-open if it was truncated/replaced) before seeking to saved offsets
  3. In tail loops, poll length growth and only seek within [0, currentLength]

Example fix

// before
in.seek(savedOffset); // saved when the file was longer

// after
long len = fs.getFileStatus(path).getLen();
in.seek(Math.min(savedOffset, len));
Defensive patterns

Strategy: validation

Validate before calling

long len = fs.getFileStatus(path).getLen();
if (targetPos > len) {
  targetPos = len; // clamp: seek to EOF instead of past it
}
if (targetPos < 0) {
  throw new IllegalArgumentException("negative seek: " + targetPos);
}
in.seek(targetPos);

Type guard

static boolean isSeekPastEof(IOException e) {
  return e instanceof EOFException
      && e.getMessage() != null && e.getMessage().equals("Cannot seek after EOF");
}

Try / catch

try {
  in.seek(targetPos);
} catch (EOFException e) {
  if (isSeekPastEof(e)) {
    long len = fs.getFileStatus(path).getLen();
    in.seek(Math.min(targetPos, len)); // file shrank: clamp
  } else throw e;
}

Prevention

When it happens

Trigger: seek(target) where target exceeds the current length: offsets cached from an earlier, longer version of the file; racing a truncate; index/offset files pointing past the current data extent.

Common situations: Tailing loops that remember an old file length across rotation/truncation; readers using saved checkpoints after external truncation; off-by-one seek to len instead of len-1.

Related errors


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