{"record":{"id":"9a28de34c70ffdc2","repo":"apache/hadoop","slug":"cannot-seek-to-a-negative-offset-targetpos-9a28de","errorCode":null,"errorMessage":"Cannot seek to a negative offset <targetPos>","messagePattern":"Cannot seek to a negative offset <targetPos>","errorType":"exception","errorClass":"EOFException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AInputStream.java","lineNumber":289,"sourceCode":"    changeTracker.processResponse(wrappedStream.response(), operation,\n        targetPos);\n\n    contentRangeStart = targetPos;\n    this.pos = targetPos;\n  }\n\n  @Override\n  public synchronized long getPos() throws IOException {\n    return (nextReadPos < 0) ? 0 : nextReadPos;\n  }\n\n  @Override\n  public synchronized void seek(long targetPos) throws IOException {\n    checkNotClosed();\n\n    // Do not allow negative seek\n    if (targetPos < 0) {\n      throw new EOFException(FSExceptionMessages.NEGATIVE_SEEK\n          + \" \" + targetPos);\n    }\n\n    if (this.getContentLength() <= 0) {\n      return;\n    }\n\n    // Lazy seek\n    nextReadPos = targetPos;\n  }\n\n  /**\n   * Seek without raising any exception. This is for use in\n   * {@code finally} clauses\n   * @param positiveTargetPos a target position which must be positive.\n   */\n  private void seekQuietly(long positiveTargetPos) {\n    try {","sourceCodeStart":271,"sourceCodeEnd":307,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/S3AInputStream.java#L271-L307","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Fix the offset computation (e.g. validate fileStatus.getLen() >= FOOTER_SIZE before computing fileLength - trailerSize)","Use seek(0) to rewind - negative offsets are never accepted","Log getPos() and the file length next to the computed seek target to locate where the negative value is produced"],"exampleFix":"// before\nlong footerStart = fileLen - FOOTER_SIZE; // underflows on tiny files\nin.seek(footerStart); // EOFException: Cannot seek to a negative offset\n\n// after\nif (fileLen < FOOTER_SIZE) {\n  throw new IOException(\"File too small to contain a footer: \" + fileLen);\n}\nin.seek(fileLen - FOOTER_SIZE);","handlingStrategy":"validation","validationCode":"long target = computeTargetPos(fileLen, bytesWanted);\nFileStatus st = fs.getFileStatus(path);\nif (target < 0 || target > st.getLen()) {\n  throw new IOException(\"Invalid seek target \" + target\n      + \" for file \" + path + \" of length \" + st.getLen());\n}\nin.seek(target);","typeGuard":null,"tryCatchPattern":"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); }","preventionTips":["Never derive seek targets by subtraction without first comparing against the file length","Guard every seek(p) with 0 <= p <= fileStatus.getLen()","Unit-test footer/header readers with 0-byte and tiny files"],"tags":["s3a","hadoop-aws","seek","input-stream","eofexception","positioned-read"],"backgroundTag":"negative-seek-offset","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}