{"record":{"id":"b849a3a48b43d6f6","repo":"apache/hadoop","slug":"end-of-file-reached-before-reading-fully","errorCode":null,"errorMessage":"End of file reached before reading fully.","messagePattern":"End of file reached before reading fully\\.","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":906,"sourceCode":"      final int offset,\n      final int length)\n      throws IOException {\n    long startTime = System.currentTimeMillis();\n    long threadId = Thread.currentThread().getId();\n    checkNotClosed();\n    validatePositionedReadArgs(position, buffer, offset, length);\n    if (length == 0) {\n      return;\n    }\n    int nread = 0;\n    synchronized (this) {\n      long oldPos = getPos();\n      try {\n        seek(position);\n        while (nread < length) {\n          int nbytes = read(buffer, offset + nread, length - nread);\n          if (nbytes < 0) {\n            throw new EOFException(\n                FSExceptionMessages.EOF_IN_READ_FULLY);\n          }\n          nread += nbytes;\n        }\n      } finally {\n        seekQuietly(oldPos);\n      }\n    }\n\n    long endTime = System.currentTimeMillis();\n    LOG.debug(\n        \"ReadFully uri:{}, contentLength:{}, destLen:{}, readLen:{}, \"\n            + \"position:{}, thread:{}, timeUsedMilliSec:{}\",\n        uri, contentLength, length, nread, position, threadId,\n        endTime - startTime);\n  }\n\n  /**","sourceCodeStart":888,"sourceCodeEnd":924,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-cloud-storage-project/hadoop-huaweicloud/src/main/java/org/apache/hadoop/fs/obs/OBSInputStream.java#L888-L924","documentation":"OBSInputStream.readFully(position, buffer, offset, length) seeks to the requested position and loops read() until exactly length bytes are delivered; if read() returns -1 while nread < length it throws EOFException(FSExceptionMessages.EOF_IN_READ_FULLY, 'End of file reached before reading fully.'). readFully's contract is all-or-nothing: unlike read(), a short result at EOF is an error. The original position is restored in a finally via seekQuietly, so the stream stays usable after the exception.","triggerScenarios":"readFully(pos, buf, off, len) where pos+len exceeds the object's contentLength (e.g. reading a fixed-size footer/header from a truncated file); stale FileStatus length cached before the object was overwritten with a shorter one; computing reads from file size minus a constant when the file is smaller than that constant.","commonSituations":"Reading fixed-size file formats (magic bytes, footers) from files that are shorter than expected due to interrupted uploads; racing overwrites where another writer replaced the object mid-read; split computations using outdated lengths; zero-byte objects read with length>0.","solutions":["Clamp the request to the actual size: len = Math.min(len, fileStatus.getLen() - pos), and skip when len <= 0","Re-stat the file (getFileStatus) immediately before readFully when concurrent overwrites are possible","Treat this EOFException as a data condition: the file is shorter than the format promises — verify producer-side upload completion (commit markers) before consuming","For optional footers, fall back to a bounded read (loop read()) that tolerates EOF instead of readFully"],"exampleFix":"// before\nin.readFully(pos, buf, 0, FOOTER_LEN); // file shorter than pos+FOER_LEN -> EOFException\n\n// after\nFileStatus st = fs.getFileStatus(path);\nint len = (int) Math.min(FOOTER_LEN, st.getLen() - pos);\nif (len < FOOTER_LEN) {\n  throw new IOException(\"file \" + path + \" too small: \" + st.getLen());\n}\nin.readFully(pos, buf, 0, len);","handlingStrategy":"validation","validationCode":"FileStatus st = fs.getFileStatus(path);\nlong avail = st.getLen() - position;\nif (length > avail) {\n  throw new EOFException(\"file \" + path + \" has only \" + avail\n      + \" bytes at position \" + position + \"; requested \" + length);\n}\nin.readFully(position, buffer, offset, length);","typeGuard":null,"tryCatchPattern":"try {\n  in.readFully(position, buffer, offset, length);\n} catch (EOFException e) {\n  // file shorter than format expects: fail with context, keep original position (stream restores it)\n  throw new IOException(\"truncated object at \" + path + \": \" + e.getMessage(), e);\n}","preventionTips":["Clamp readFully lengths to file length minus position","Re-stat files before reading when concurrent overwrites are possible","Only consume files after their commit marker exists (producer completed upload)"],"tags":["eof","read","readfully","hadoop-obs"],"backgroundTag":"unexpected-eof","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}