{"record":{"id":"426b9aa559ddd80c","repo":"apache/iceberg","slug":"parquet-bug-stream-is-bad-incorrect-bytes-remai","errorCode":null,"errorMessage":"[Parquet bug] Stream is bad: incorrect bytes remaining <remaining>","messagePattern":"\\[Parquet bug\\] Stream is bad: incorrect bytes remaining <remaining>","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java","lineNumber":224,"sourceCode":"      } else if (!nextBuffer()) {\n        // there are no more buffers\n        throw new EOFException();\n      }\n    }\n\n    return sliceBuffers;\n  }\n\n  @Override\n  public List<ByteBuffer> remainingBuffers() {\n    if (position >= length) {\n      return Collections.emptyList();\n    }\n\n    try {\n      return sliceBuffers(length - position);\n    } catch (EOFException e) {\n      throw new RuntimeException(\n          \"[Parquet bug] Stream is bad: incorrect bytes remaining \" + (length - position));\n    }\n  }\n\n  @Override\n  public int read(byte[] bytes, int off, int len) {\n    if (len <= 0) {\n      if (len < 0) {\n        throw new IndexOutOfBoundsException(\"Read length must be greater than 0: \" + len);\n      }\n      return 0;\n    }\n\n    if (current == null) {\n      return -1;\n    }\n\n    int bytesRead = 0;","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java#L206-L242","documentation":"remainingBuffers() delegates to sliceBuffers(length - position) and assumes the remaining bytes must exist because position/length bookkeeping says so. If sliceBuffers hits EOF anyway, the internal accounting is inconsistent, so it rethrows as a RuntimeException labeled a '[Parquet bug] Stream is bad' with the incorrect remaining count. This is an internal invariant violation, not user error.","triggerScenarios":"Calling remainingBuffers() on a stream whose position/length no longer match actual buffer contents — e.g. buffers were consumed externally, or position advanced past what the buffer chain can supply.","commonSituations":"Bugs in Parquet reader implementations mis-tracking consumed bytes; sharing a MultiBufferInputStream between readers that each advance position; custom InputFile/stream wrappers that return inconsistent buffer counts.","solutions":["Report the Parquet reader bug with the file and stack trace (this is an internal invariant failure)","Ensure no code path reads/advances the stream outside the expected reader lifecycle","Don't share one MultiBufferInputStream across concurrent or nested readers","Recompute the stream from the original buffers/file if the state went bad (retry the task)"],"exampleFix":"// before\n// stream state inconsistent -> RuntimeException [Parquet bug]\nList<ByteBuffer> bufs = stream.remainingBuffers();\n// after\n// re-create the stream from source data instead of trusting bad state\ntry (MultiBufferInputStream fresh = MultiBufferInputStream.of(bufferList)) {\n  List<ByteBuffer> bufs = fresh.remainingBuffers();\n}","handlingStrategy":"try-catch","validationCode":"if (stream.position() > stream.getLength()) {\n  throw new IllegalStateException(\"Stream position \" + stream.position() + \" exceeds length \" + stream.getLength());\n}","typeGuard":null,"tryCatchPattern":"try {\n  return stream.remainingBuffers();\n} catch (RuntimeException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"[Parquet bug]\")) {\n    throw new IllegalStateException(\"Stream bookkeeping broken; re-open input\", e);\n  }\n  throw e;\n}","preventionTips":["Never advance the stream outside the owning reader","Don't share MultiBufferInputStream across threads or nested readers","If seen, file a Parquet/Iceberg reader bug with repro file"],"tags":["internal-bug","parquet","invariant-violation","byte-buffers"],"backgroundTag":"internal-invariant-violation","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"}