apache/hadoop · error · EOFException

Cannot seek to a negative offset

Error message

Cannot seek to a negative offset

What it means

SFTPInputStream.seek(long position) throws EOFException carrying FSExceptionMessages.NEGATIVE_SEEK ('Cannot seek to a negative offset') when position < 0. Note the exception type is EOFException, not IllegalArgumentException — the stream follows the FileSystem convention that seek positions must be non-negative.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/sftp/SFTPInputStream.java:64

  SFTPInputStream(ChannelSftp channel, Path path, FileSystem.Statistics stats)
      throws IOException {
    try {
      this.channel = channel;
      this.path = path;
      this.stats = stats;
      this.wrappedStream = channel.get(path.toUri().getPath());
      SftpATTRS stat = channel.lstat(path.toString());
      this.contentLength = stat.getSize();
    } catch (SftpException e) {
      throw new IOException(e);
    }
  }

  @Override
  public synchronized void seek(long position) throws IOException {
    checkNotClosed();
    if (position < 0) {
      throw new EOFException(FSExceptionMessages.NEGATIVE_SEEK);
    }
    nextPos = position;
  }

  @Override
  public synchronized int available() throws IOException {
    checkNotClosed();
    long remaining = contentLength - nextPos;
    if (remaining > Integer.MAX_VALUE) {
      return Integer.MAX_VALUE;
    }
    return (int) remaining;
  }

  private void seekInternal() throws IOException {
    if (pos == nextPos) {
      return;
    }

View on GitHub (pinned to 2add963021)

Solutions

  1. Clamp the computed position before seeking: long target = Math.max(0, pos - n);
  2. Fix the underlying offset arithmetic — usually an off-by-one or a missing guard for the first record/split (start == 0).
  3. Use seek(0) when the intent is to reset to the beginning of the stream.

Example fix

// before
stream.seek(pos - bytesToSkip); // throws when bytesToSkip > pos

// after
stream.seek(Math.max(0, pos - bytesToSkip));
Defensive patterns

Strategy: validation

Validate before calling

long target = Math.max(0, computedOffset);
stream.seek(target);

Try / catch

try {
  stream.seek(pos);
} catch (EOFException e) {
  // negative position: fix offset arithmetic, then clamp and retry at 0
  stream.seek(0);
}

Prevention

When it happens

Trigger: Calling seek(negative) directly, or computing a position that underflows: seek(pos - n) where n > pos, first-split start offsets computed as -1, and rewind/skip arithmetic with off-by-one errors.

Common situations: Custom line readers that recompute offsets after reading a trailing newline; input-format split logic where the first record's start is calculated before position 0; porting seek logic from a stream that permitted negative values or wrapped them.

Related errors


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