apache/hadoop · error · EOFException

Cannot seek to a negative offset <targetPos>

Error message

Cannot seek to a negative offset <targetPos>

What it means

Thrown by S3AInputStream.seek(long) when the requested target position is negative. Hadoop's S3A connector implements lazy seeking: seek() only validates the target and records nextReadPos for the next read. A negative offset can never be valid on an S3 object, so it fails fast with an EOFException (FSExceptionMessages.NEGATIVE_SEEK) instead of touching the store.

Source

Thrown at hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AInputStream.java:289

    changeTracker.processResponse(wrappedStream.response(), operation,
        targetPos);

    contentRangeStart = targetPos;
    this.pos = targetPos;
  }

  @Override
  public synchronized long getPos() throws IOException {
    return (nextReadPos < 0) ? 0 : nextReadPos;
  }

  @Override
  public synchronized void seek(long targetPos) throws IOException {
    checkNotClosed();

    // Do not allow negative seek
    if (targetPos < 0) {
      throw new EOFException(FSExceptionMessages.NEGATIVE_SEEK
          + " " + targetPos);
    }

    if (this.getContentLength() <= 0) {
      return;
    }

    // Lazy seek
    nextReadPos = targetPos;
  }

  /**
   * Seek without raising any exception. This is for use in
   * {@code finally} clauses
   * @param positiveTargetPos a target position which must be positive.
   */
  private void seekQuietly(long positiveTargetPos) {
    try {

View on GitHub (pinned to 2add963021)

Solutions

  1. Guard the arithmetic: compare the computed target against the real file length before calling seek, and fail with a clear domain error when the file is too small
  2. Fix the offset computation (e.g. validate fileStatus.getLen() >= FOOTER_SIZE before computing fileLength - trailerSize)
  3. Use seek(0) to rewind - negative offsets are never accepted
  4. Log getPos() and the file length next to the computed seek target to locate where the negative value is produced

Example fix

// before
long footerStart = fileLen - FOOTER_SIZE; // underflows on tiny files
in.seek(footerStart); // EOFException: Cannot seek to a negative offset

// after
if (fileLen < FOOTER_SIZE) {
  throw new IOException("File too small to contain a footer: " + fileLen);
}
in.seek(fileLen - FOOTER_SIZE);
Defensive patterns

Strategy: validation

Validate before calling

long target = computeTargetPos(fileLen, bytesWanted);
FileStatus st = fs.getFileStatus(path);
if (target < 0 || target > st.getLen()) {
  throw new IOException("Invalid seek target " + target
      + " for file " + path + " of length " + st.getLen());
}
in.seek(target);

Try / catch

try { in.seek(pos); } catch (EOFException e) { /* caller-side logic bug: log pos, getPos(), file length; do not retry */ throw new IllegalArgumentException("bad seek target", e); }

Prevention

When it happens

Trigger: Calling seek(n) with n < 0 on an S3AInputStream or an FSDataInputStream wrapping it. Typically the value comes from offset arithmetic that underflows, e.g. fileLength - bytesWanted where the file is smaller than the assumed header/footer size, or pos - remaining after a short read.

Common situations: Reading fixed-size trailers (Avro/ORC/Parquet footers) from tiny, empty, or truncated files; custom RecordReaders computing split positions; passing -1 as a 'rewind to start' sentinel; long/integer math bugs in positioned-read loops.

Related errors


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