{"record":{"id":"fbc19b6ac3e6319a","repo":"apache/iceberg","slug":"reached-the-end-of-stream-with-x-bytes-left-to-rea","errorCode":null,"errorMessage":"Reached the end of stream with X bytes left to read","messagePattern":"Reached the end of stream with X bytes left to read","errorType":"exception","errorClass":"EOFException","httpStatus":null,"severity":"error","filePath":"gcp/src/main/java/org/apache/iceberg/gcp/gcs/GCSInputStream.java","lineNumber":168,"sourceCode":"    int bytesRead = read(channel, byteBuffer, off, len);\n    if (bytesRead == -1) {\n      return -1;\n    }\n\n    pos += bytesRead;\n    readBytes.increment(bytesRead);\n    readOperations.increment();\n    return bytesRead;\n  }\n\n  @Override\n  public void readFully(long position, byte[] buffer, int offset, int length) throws IOException {\n    try (ReadChannel readChannel = openChannel()) {\n      readChannel.seek(position);\n      readChannel.limit(position + length);\n      int bytesRead = read(readChannel, ByteBuffer.wrap(buffer), offset, length);\n      if (bytesRead < length) {\n        throw new EOFException(\n            \"Reached the end of stream with \" + (length - bytesRead) + \" bytes left to read\");\n      }\n      if (bytesRead > 0) {\n        readBytes.increment(bytesRead);\n        readOperations.increment();\n      }\n    }\n  }\n\n  @Override\n  public int readTail(byte[] buffer, int offset, int length) throws IOException {\n    if (blobSize == null) {\n      blobSize = storage.get(blobId).getSize();\n    }\n    long startPosition = Math.max(0, blobSize - length);\n    try (ReadChannel readChannel = openChannel()) {\n      readChannel.seek(startPosition);\n      int bytesRead = read(readChannel, ByteBuffer.wrap(buffer), offset, length);","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/gcp/src/main/java/org/apache/iceberg/gcp/gcs/GCSInputStream.java#L150-L186","documentation":"GCSInputStream.readFully(position, buffer, offset, length) reads an exact byte range from a GCS ReadChannel. If fewer than the requested bytes are returned before the stream ends, it throws EOFException('Reached the end of stream with X bytes left to read'), indicating a truncated object or a read range beyond the object's size.","triggerScenarios":"readFully requests a range whose end exceeds the object's actual size, or the ReadChannel returns a short read due to truncation/corruption, called internally by decode-style readers.","commonSituations":"Stale length metadata (file shrunk/replaced between listing and read), reading past the end of a file after a bad offset calculation, or partially uploaded objects.","solutions":["Verify the object size matches the length being requested — refresh file metadata if the object may have been replaced","Check for concurrent overwrite/delete of the object while reading; use generation-consistent reads","Fix offset arithmetic in the caller so ranges stay within the object bounds","Wrap in try-catch for EOFException and re-plan/refresh the scan rather than retrying blindly"],"exampleFix":"// before\nin.readFully(position, buffer, offset, length); // may pass EOF\n// after\nlong available = objectSize - position;\nif (length > available) {\n  throw new IOException(\"Range exceeds object size: \" + position + \"+\" + length + \" > \" + objectSize);\n}\nin.readFully(position, buffer, offset, length);","handlingStrategy":"try-catch","validationCode":"if (position + length > fileSize) { throw new IOException(\"Read range past EOF: \" + position + \"+\" + length + \" > \" + fileSize); }","typeGuard":null,"tryCatchPattern":"try { in.readFully(position, buffer, offset, length); } catch (EOFException e) { LOG.error(\"Truncated GCS read at {}\", position, e); /* refresh metadata or re-plan */ }","preventionTips":["Refresh file metadata if objects may be replaced concurrently","Compute ranges from the actual object size, not cached lengths","Detect partially uploaded objects before reading"],"tags":["gcp","gcs","io","eof","stream"],"backgroundTag":"unexpected-end-of-stream","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}