{"record":{"id":"0c5bda4eab8c9a7c","repo":"apache/hadoop","slug":"cannot-seek-after-eof-0c5bda","errorCode":null,"errorMessage":"Cannot seek after EOF","messagePattern":"Cannot seek after EOF","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ChecksumFs.java","lineNumber":316,"sourceCode":"      return super.skip(n);\n    }\n    \n    /**\n     * Seek to the given position in the stream.\n     * The next read() will be from that position.\n     * \n     * <p>This method does not allow seek past the end of the file.\n     * This produces IOException.\n     *\n     * @param      pos   the postion to seek to.\n     * @exception  IOException  if an I/O error occurs or seeks after EOF\n     *             ChecksumException if the chunk to seek to is corrupted\n     */\n\n    @Override\n    public synchronized void seek(long pos) throws IOException { \n      if (pos>getFileLength()) {\n        throw new IOException(\"Cannot seek after EOF\");\n      }\n      super.seek(pos);\n    }\n\n  }\n\n  @Override\n  public boolean truncate(Path f, long newLength) throws IOException {\n    throw new UnsupportedOperationException(\"Truncate is not supported \"\n        + \"by ChecksumFs\");\n  }\n\n  /**\n   * Opens an FSDataInputStream at the indicated Path.\n   * @param f the file name to open\n   * @param bufferSize the size of the buffer to be used.\n   */\n  @Override","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/ChecksumFs.java#L298-L334","documentation":"ChecksumFs's ChecksumFSInputChecker.seek(long) checks the requested position against the data file's length and throws a plain IOException ('Cannot seek after EOF') when pos exceeds it. This mirrors java.io.RandomAccessFile.seek semantics the checker adds because the underlying buffered reader cannot represent a position past the end. The length is fetched via getFileStatus, so a stale cached length is not the issue - the pos really is beyond the file.","triggerScenarios":"Calling FSDataInputStream.seek(pos) on a stream opened from a checksummed local fs (FileContext.open on file://, ChecksumFs) where pos > file length: reading a fixed-size record at an offset computed from a larger/older version of the file, seeking to end-of-file plus one, or integer math (e.g., length() vs getPos() confusion) producing an out-of-range value.","commonSituations":"Record readers that compute splits/offsets from a stale FileStatus after the file was truncated or replaced; unit tests seeking to fileLen exactly works but len+1 fails; code mixing 0-based and 1-based end offsets.","solutions":["Clamp before seeking: long pos = Math.min(requested, in.available() positions) - practically, fetch fs.getFileStatus(f).getLen() once and Math.min(pos, len) it.","Fix the offset arithmetic: seek(end) is legal (pos == length is allowed, pos > length is not); check off-by-one where end = start + length instead of start + length - 1 style bugs.","If the file was expected to be bigger, re-stat it - it may have been truncated/rewritten by another process since the length was cached."],"exampleFix":"// before\nlong pos = header.startOffset() + header.size(); // may exceed file\nin.seek(pos); // IOException: Cannot seek after EOF\n\n// after\nlong len = in.getPos() >= 0 ? fileStatus.getLen() : 0;\nin.seek(Math.min(pos, fileStatus.getLen()));","handlingStrategy":"validation","validationCode":"long len = fc.getFileStatus(path).getLen();\nif (pos > len) {\n  pos = len; // clamp instead of seek-after-EOF\n}","typeGuard":null,"tryCatchPattern":"try {\n  in.seek(pos);\n} catch (IOException e) { // 'Cannot seek after EOF'\n  // clamp pos to in.available()/file length and re-seek\n}","preventionTips":["Re-stat the file before computing seek offsets; lengths go stale when files are rewritten.","Treat length as an exclusive bound: seek(len) is legal, seek(len+1) is not.","Centralize offset math in one helper so off-by-ones fail one test, not many jobs."],"tags":["hadoop","filesystem","seek","eof","bounds","local-filesystem"],"backgroundTag":"seek-past-end-of-file","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}