{"record":{"id":"c949f747d40935a5","repo":"apache/iceberg","slug":"failed-to-read-d-bytes-d-bytes-in-stream","errorCode":null,"errorMessage":"Failed to read %d bytes: %d bytes in stream","messagePattern":"Failed to read (.+?) bytes: (.+?) bytes in stream","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"core/src/main/java/org/apache/iceberg/io/ContentCache.java","lineNumber":257,"sourceCode":"  }\n\n  private static FileContent download(InputFile input) {\n    try (SeekableInputStream stream = input.newStream()) {\n      long fileLength = input.getLength();\n      long totalBytesToRead = fileLength;\n      List<ByteBuffer> buffers = Lists.newArrayList();\n\n      while (totalBytesToRead > 0) {\n        // read the stream in chunks\n        int bytesToRead = (int) Math.min(BUFFER_CHUNK_SIZE, totalBytesToRead);\n        byte[] buf = new byte[bytesToRead];\n        int bytesRead = IOUtil.readRemaining(stream, buf, 0, bytesToRead);\n        totalBytesToRead -= bytesRead;\n\n        if (bytesRead < bytesToRead) {\n          // Read less than it should be, possibly hitting EOF. Abandon caching by throwing\n          // IOException and let the caller fallback to non-caching input file.\n          throw new IOException(\n              String.format(\n                  Locale.ROOT,\n                  \"Failed to read %d bytes: %d bytes in stream\",\n                  fileLength,\n                  fileLength - totalBytesToRead));\n        } else {\n          buffers.add(ByteBuffer.wrap(buf));\n        }\n      }\n\n      return new FileContent(fileLength, buffers);\n    } catch (IOException ex) {\n      throw new UncheckedIOException(ex);\n    }\n  }\n}\n","sourceCodeStart":239,"sourceCodeEnd":274,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/io/ContentCache.java#L239-L274","documentation":"During ContentCache.download, the cached read got fewer bytes than the file's declared length before reaching EOF. The cache is abandoned by throwing IOException so the caller falls back to a non-caching input stream; the message reports how many bytes were actually read.","triggerScenarios":"The input stream returned by the delegate ends prematurely: file truncated or rewritten to a smaller size after length was read, or the storage client returned a short/incomplete response body.","commonSituations":"Concurrent overwrite of an object in stores without atomic replace; corrupted/incomplete multipart upload; proxy or CDN truncating responses; stale length from stale metadata.","solutions":["Retry the read; the fallback non-caching path usually succeeds.","Verify the object's current size matches the length in table metadata.","Check for writers overwriting files in place; Iceberg files must be immutable.","Investigate storage client/proxy truncation (timeouts, range request handling)."],"exampleFix":"// before\nContentCache cache = new ContentCache(0, 64 * 1024 * 1024); // cache huge files, hit truncation\n// after\nContentCache cache = new ContentCache(0, 8 * 1024 * 1024); // cache small files only","handlingStrategy":"retry","validationCode":"long actualLength = delegate.getLength();\nif (declaredLength != actualLength) { refreshMetadata(); }","typeGuard":null,"tryCatchPattern":"try {\n  return cachedInputFile.newStream();\n} catch (IOException | UncheckedIOException e) {\n  return delegate.newStream(); // non-caching fallback is built in\n}","preventionTips":["Treat Iceberg data files as immutable — never overwrite in place","Use storage with atomic replace semantics","Keep cached file sizes small to reduce truncation exposure","Retry transiently on short reads; they are often storage blips"],"tags":["io","truncated-read","cache"],"backgroundTag":"file-read-failed","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}