apache/hadoop · error · EOFException

Cannot seek to negative offset

Error message

Cannot seek to negative offset

What it means

DFSStripedInputStream.seek(long) validates the target position before moving the read cursor of an erasure-coded HDFS file: positions past EOF and negative positions are both rejected. A negative targetPos throws EOFException('Cannot seek to negative offset') even though the stream itself is healthy — the value passed in is illegal. The striped reader shares this strictness with the replicated reader (DFSInputStream), because internal stripe buffers are indexed from the file start.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/DFSStripedInputStream.java:360

    }
    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;
  }

  private int getStripedBufOffset(long offsetInBlockGroup) {

View on GitHub (pinned to 2add963021)

Solutions

  1. Clamp the computed position before seeking: Math.max(0, targetPos).
  2. Audit all seek call sites for underflow-prone arithmetic and unchecked indexOf()/lastIndexOf() results.
  3. Map sentinel values (e.g., -1 meaning 'not found') to a real decision — skip the seek or seek(0) — instead of forwarding them.
  4. As a safety net, catch EOFException around seek() and log-and-correct rather than failing the whole read job.

Example fix

// before
long newPos = currentPos - backTrack;
in.seek(newPos); // EOFException when backTrack > currentPos

// after
long newPos = Math.max(0, currentPos - backTrack);
in.seek(newPos);
Defensive patterns

Strategy: validation

Validate before calling

if (targetPos < 0) {
  throw new IllegalArgumentException(
      "seek position must be >= 0, got " + targetPos);
}
if (targetPos > in.getLen()) { // also avoids 'Cannot seek after EOF'
  targetPos = in.getLen();
}
in.seek(targetPos);

Try / catch

try {
  in.seek(targetPos);
} catch (EOFException e) {
  LOG.warn("Invalid seek target {} on {} - resetting to 0", targetPos, path, e);
  in.seek(0);
}

Prevention

When it happens

Trigger: Calling seek(n) with n < 0 on an FSDataInputStream opened from an EC-coded HDFS file. Typical producers: backtracking math like pos - backTrack where backTrack > pos, and passing a -1 sentinel (e.g., the result of String.indexOf()/lastIndexOf()) directly into seek().

Common situations: Custom skip/rewind logic that subtracts from the current position without clamping; index-derived offsets not checked for -1; code ported from APIs where seek wrapped around or was a no-op on bad input.

Related errors


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