{"record":{"id":"24aac01df01581ae","repo":"apache/hadoop","slug":"cannot-seek-to-a-negative-offset-pos","errorCode":null,"errorMessage":"Cannot seek to a negative offset \" + pos","messagePattern":"Cannot seek to a negative offset \" \\+ pos","errorType":"exception","errorClass":"EOFException","httpStatus":null,"severity":"error","filePath":"hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/impl/streams/AnalyticsStream.java","lineNumber":107,"sourceCode":"    try {\n      bytesRead = inputStream.read();\n    } catch (IOException ioe) {\n      onReadFailure(ioe);\n      throw ioe;\n    }\n\n    if (bytesRead != -1) {\n      incrementBytesRead(1);\n    }\n\n    return bytesRead;\n  }\n\n  @Override\n  public void seek(long pos) throws IOException {\n    throwIfClosed();\n    if (pos < 0) {\n      throw new EOFException(FSExceptionMessages.NEGATIVE_SEEK\n          + \" \" + pos);\n    }\n    inputStream.seek(pos);\n  }\n\n\n  @Override\n  public synchronized long getPos() {\n    if (!closed) {\n      lastReadCurrentPos = inputStream.getPos();\n    }\n    return lastReadCurrentPos;\n  }\n\n\n  /**\n   * Reads the last n bytes from the stream into a byte buffer. Blocks until end of stream is\n   * reached. Leaves the position of the stream unaltered.","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-tools/hadoop-aws/src/main/java/org/apache/hadoop/fs/s3a/impl/streams/AnalyticsStream.java#L89-L125","documentation":"AnalyticsStream is the input stream over Amazon S3 Select (S3A selectQuery) results. Its seek() refuses negative positions with EOFException(FSExceptionMessages.NEGATIVE_SEEK + \" \" + pos) before delegating to the underlying AmazonS3 Select stream. A negative seek position is always a caller bug.","triggerScenarios":"Calling seek(negative) on the FSDataInputStream returned by S3AFileSystem.select(); passing a negative offset computed from a variable (e.g. pos - readLength underflow, a getPos() of -1 sentinel leaking into arithmetic); random-access readers treating the select result as seekable beyond the supported contract.","commonSituations":"Custom InputFormat/RecordReader computing split starts incorrectly and seeking negative; reusing code that seeks to (currentPos - delta) where delta > currentPos; unit tests poking at seek edges. Note S3 Select results are usually consumed sequentially.","solutions":["Fix the caller: clamp positions to >= 0 before seek() (long offset arithmetic can underflow).","Check FSDataInputStream.getPos() and FileStatus offsets before computing seeks in RecordReaders.","If you need true random access, read the object normally (open()) instead of using a selectQuery result stream.","Catch EOFException defensively and log the requested position to find the bad arithmetic."],"exampleFix":"// before\nlong target = currentPos - bytesToRewind; // can go negative\nstream.seek(target);\n\n// after\nlong target = Math.max(0, currentPos - bytesToRewind);\nstream.seek(target);","handlingStrategy":"validation","validationCode":"if (pos < 0) {\n  throw new IllegalArgumentException(\"seek position must be >= 0, got \" + pos);\n}\nin.seek(pos);","typeGuard":null,"tryCatchPattern":"try {\n  in.seek(pos);\n} catch (EOFException e) {\n  // negative seek is a caller bug: log position and fix computation\n  LOG.error(\"bad seek {}\", pos, e);\n  throw e;\n}","preventionTips":["Clamp all seek targets to [0, fileLen).","Use long (not int) for offsets to avoid overflow/underflow.","Prefer sequential consumption of S3 Select result streams."],"tags":["hadoop-aws","s3-select","seek","stream","off-by-error"],"backgroundTag":"negative-seek-offset","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}