{"record":{"id":"a1656b28df0f1a04","repo":"apache/hadoop","slug":"cannot-seek-to-a-negative-offset-a1656b","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-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/CryptoInputStream.java","lineNumber":526,"sourceCode":"          + \" does not support positioned readFully.\");\n    }\n    ((PositionedReadable) in).readFully(position, buffer, offset, length);\n    if (length > 0) {\n      // This operation does not change the current offset of the file\n      decrypt(position, buffer, offset, length);\n    }\n  }\n\n  @Override\n  public void readFully(long position, byte[] buffer) throws IOException {\n    readFully(position, buffer, 0, buffer.length);\n  }\n\n  /** Seek to a position. */\n  @Override\n  public void seek(long pos) throws IOException {\n    if (pos < 0) {\n      throw new EOFException(FSExceptionMessages.NEGATIVE_SEEK);\n    }\n    checkStream();\n    /*\n     * If data of target pos in the underlying stream has already been read\n     * and decrypted in outBuffer, we just need to re-position outBuffer.\n     */\n    if (pos <= streamOffset && pos >= (streamOffset - outBuffer.remaining())) {\n      int forward = (int) (pos - (streamOffset - outBuffer.remaining()));\n      if (forward > 0) {\n        outBuffer.position(outBuffer.position() + forward);\n      }\n    } else {\n      if (!(in instanceof Seekable)) {\n        throw new UnsupportedOperationException(in.getClass().getCanonicalName()\n            + \" does not support seek.\");\n      }\n      ((Seekable) in).seek(pos);\n      resetStreamOffset(pos);","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/crypto/CryptoInputStream.java#L508-L544","documentation":"CryptoInputStream.seek(pos) validates pos >= 0 first and throws EOFException with FSExceptionMessages.NEGATIVE_SEEK (\"Cannot seek to a negative offset\") for negative positions. This is a caller-input error independent of wrapped-stream capabilities; Hadoop filesystem code deliberately uses EOFException for negative seeks, which can mislead readers expecting IllegalArgumentException.","triggerScenarios":"seek(-1) or any negative position, usually from upstream arithmetic: getPos() minus an overshoot, seek(pos - n) with n > pos, or negative split/index offsets read from a corrupt index file.","commonSituations":"Reader code computing 'current position - bytesToSkip' without clamping at 0; off-by-one loops in custom InputFormats; offsets from malformed sidecar index files.","solutions":["Clamp the computed offset to >= 0 before seek: Math.max(0L, target)","Fix the upstream arithmetic that produced the negative position (overshoot in skip/read accounting)","If the intent was 'go back n bytes', verify getPos() >= n before computing the target"],"exampleFix":"// before\nlong target = stream.getPos() - bytesConsumed; // can go negative\nstream.seek(target);\n\n// after\nlong target = Math.max(0L, stream.getPos() - bytesConsumed);\nstream.seek(target);","handlingStrategy":"validation","validationCode":"if (targetPos < 0) {\n  throw new IllegalArgumentException(\"seek offset must be >= 0, got \" + targetPos);\n}\nin.seek(targetPos);","typeGuard":null,"tryCatchPattern":"try {\n  in.seek(pos);\n} catch (EOFException e) {\n  if (FSExceptionMessages.NEGATIVE_SEEK.equals(e.getMessage())) {\n    throw new IllegalArgumentException(\"computed a negative offset: \" + pos, e);\n  }\n  throw e;\n}","preventionTips":["Clamp computed offsets with Math.max(0, value) before seek","Validate split/index offsets for >= 0 when loading them from sidecar files","Unit-test backward navigation logic (getPos() - n) at position 0"],"tags":["crypto","stream","seek","validation","hadoop"],"backgroundTag":"invalid-seek-offset","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}