apache/hadoop · error · EOFException

Negative Position

Error message

Negative Position

What it means

ByteRangeInputStream.seek() deliberately does not validate the position; it just records startPos/currentPos and marks the stream SEEK. The check happens lazily on the next read, when openInputStream(startPos) throws EOFException for any negative offset. So this error means seek(negative) (or an equivalent state) was followed by a read on a WebHDFS input stream.

Source

Thrown at hadoop-hdfs-project/hadoop-hdfs-client/src/main/java/org/apache/hadoop/hdfs/web/ByteRangeInputStream.java:133

      if (in != null) {
        in.close();
      }
      InputStreamAndFileLength fin = openInputStream(startPos);
      in = fin.in;
      fileLength = fin.length;
      status = StreamStatus.NORMAL;
      break;
    case CLOSED:
      throw new IOException("Stream closed");
    }
    return in;
  }

  @VisibleForTesting
  protected InputStreamAndFileLength openInputStream(long startOffset)
      throws IOException {
    if (startOffset < 0) {
      throw new EOFException("Negative Position");
    }
    // Use the original url if no resolved url exists, eg. if
    // it's the first time a request is made.
    final boolean resolved = resolvedURL.getURL() != null;
    final URLOpener opener = resolved? resolvedURL: originalURL;

    final HttpURLConnection connection = opener.connect(startOffset, resolved);
    resolvedURL.setURL(getResolvedUrl(connection));

    InputStream in = connection.getInputStream();
    final Long length;
    final Map<String, List<String>> headers = connection.getHeaderFields();
    if (isChunkedTransferEncoding(headers)) {
      // file length is not known
      length = null;
    } else {
      // for non-chunked transfer-encoding, get content-length
      final String cl = connection.getHeaderField(HttpHeaders.CONTENT_LENGTH);

View on GitHub (pinned to 2add963021)

Solutions

  1. Validate the offset before seeking: if (pos < 0) throw/fallback — positions are non-negative by contract
  2. Fix the arithmetic: when reading backwards, clamp to 0 with Math.max(0, getPos() - n)
  3. Treat -1 from any matcher/index API as 'not found' and never feed it to seek()

Example fix

// before
long pos = Math.max(0, in.getPos() - tailLen);
in.seek(pos);

// after
long pos = in.getPos() - tailLen;
if (pos < 0) {
  throw new IllegalArgumentException("seek offset " + pos + " is negative");
}
in.seek(pos);
Defensive patterns

Strategy: validation

Validate before calling

if (targetPos < 0) {
  throw new IllegalArgumentException("seek position must be >= 0, got " + targetPos);
}
in.seek(targetPos);

Try / catch

try {
  in.seek(pos); in.read(buf);
} catch (EOFException e) {
  if ("Negative Position".equals(e.getMessage())) {
    throw new IllegalArgumentException("computed a negative seek offset: " + pos, e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Call seek(p) with p < 0 on a WebHDFS FSDataInputStream, then read — e.g., computing an offset with getPos() - n where n exceeds the current position, or seeding a seek from an uninitialized -1 variable.

Common situations: Offset arithmetic that underflows near the start of the file (reading the last N bytes of a prefix), passing -1 sentinels from parsers/regex match results into seek, or position values derived from user input without validation.

Related errors


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