{"record":{"id":"4907e30406d7bea2","repo":"apache/hadoop","slug":"cannot-seek-to-a-negative-offset-4907e3","errorCode":null,"errorMessage":"Cannot seek to a negative offset {}","messagePattern":"Cannot seek to a negative offset (.+?)","errorType":"exception","errorClass":"EOFException","httpStatus":null,"severity":"error","filePath":"hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSInputStream.java","lineNumber":272,"sourceCode":"        streamCurrentPos,\n        nextReadPos,\n        threadId,\n        endTime - startTime\n    );\n  }\n\n  @Override\n  public synchronized long getPos() {\n    return nextReadPos < 0 ? 0 : nextReadPos;\n  }\n\n  @Override\n  public synchronized void seek(final long targetPos) throws IOException {\n    checkNotClosed();\n\n    // Do not allow negative seek\n    if (targetPos < 0) {\n      throw new EOFException(\n          FSExceptionMessages.NEGATIVE_SEEK + \" \" + targetPos);\n    }\n\n    if (this.contentLength <= 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 {@code finally}\n   * clauses\n   *\n   * @param positiveTargetPos a target position which must be positive.\n   */\n  private void seekQuietly(final long positiveTargetPos) {","sourceCodeStart":254,"sourceCodeEnd":290,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSInputStream.java#L254-L290","documentation":"OBSInputStream.seek first calls checkNotClosed() then rejects negative targets: seek(targetPos < 0) throws EOFException(FSExceptionMessages.NEGATIVE_SEEK + ' ' + targetPos). This matches the Hadoop FSDataInputStream contract that negative seeks are invalid. Note the EOFException type (not IOException subclass of choice one might expect) — catch blocks for EOF during reads will also catch this. When contentLength <= 0 the seek is a no-op after the check, so the error is purely about the caller passing a negative position.","triggerScenarios":"fs.open(...).seek(negativeValue), typically from arithmetic that computes target = current - delta without clamping at 0; record readers seeking to (index-1)-based offsets; parquet/orc readers computing row-group starts where an empty-file edge case yields -1.","commonSituations":"Custom InputFormats deriving split starts from offsets that underflow for the last/empty split; porting code from streams where seek(-x) rewound to 0 silently; off-by-one bugs in position bookkeeping after a skipped header.","solutions":["Clamp seek targets: long target = Math.max(0, computedPosition) before calling seek","Fix the position arithmetic — find where a length/count of -1 (common 'empty' sentinel) leaks into seek","Unit-test edge splits: empty files, single-byte files, and split boundaries at 0 and contentLength","Note EOFException is thrown, so don't blanket-catch EOFException around seek+read loops and mislabel it as premature EOF"],"exampleFix":"// before\nlong target = currentPos - rewindAmount; // can be negative\nin.seek(target); // EOFException: Cannot seek to a negative offset -N\n\n// after\nlong target = Math.max(0, currentPos - rewindAmount);\nin.seek(target);","handlingStrategy":"validation","validationCode":"long clampedTarget = Math.max(0, computedTarget);\nif (clampedTarget != computedTarget) {\n  LOG.debug(\"clamped negative seek target {} -> {}\", computedTarget, clampedTarget);\n}\nin.seek(clampedTarget);","typeGuard":null,"tryCatchPattern":"try {\n  in.seek(target);\n} catch (EOFException e) {\n  if (String.valueOf(e.getMessage()).startsWith(\"Cannot seek to a negative offset\")) {\n    in.seek(0); // caller bug: negative position; clamp and continue, and fix the arithmetic\n  } else {\n    throw e;\n  }\n}","preventionTips":["Never pass unchecked arithmetic results to seek()","Treat -1 length sentinels from empty inputs as distinct from positions","Remember seek's negative-target failure is an EOFException — don't misread it as EOF data"],"tags":["positioning","seek","invalid-argument","hadoop-obs"],"backgroundTag":"negative-seek-offset","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}