{"record":{"id":"0d028a92b28f3fe4","repo":"apache/iceberg","slug":"read-length-must-be-greater-than-0-len","errorCode":null,"errorMessage":"Read length must be greater than 0: <len>","messagePattern":"Read length must be greater than 0: <len>","errorType":"exception","errorClass":"IndexOutOfBoundsException","httpStatus":null,"severity":"error","filePath":"core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java","lineNumber":233,"sourceCode":"  @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;\n    while (bytesRead < len) {\n      if (current.remaining() > 0) {\n        int bytesToRead = Math.min(len - bytesRead, current.remaining());\n        current.get(bytes, off + bytesRead, bytesToRead);\n        bytesRead += bytesToRead;\n        this.position += bytesToRead;\n      } else if (!nextBuffer()) {\n        // there are no more buffers\n        return bytesRead > 0 ? bytesRead : -1;","sourceCodeStart":215,"sourceCodeEnd":251,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/core/src/main/java/org/apache/iceberg/io/MultiBufferInputStream.java#L215-L251","documentation":"MultiBufferInputStream.read(byte[], off, len) throws IndexOutOfBoundsException when len is negative, since a negative read length is meaningless. This follows the InputStream contract; len == 0 legally returns 0 without reading. The message reports the offending len value.","triggerScenarios":"Calling read(buf, off, len) with len < 0 — usually from an unsigned-to-signed arithmetic bug (e.g. an int/long overflow making a size negative) or passing a negative remaining count computed as len = end - start with start > end.","commonSituations":"Reading sizes from metadata stored as unsigned ints but read into signed ints (large values wrap negative); computing read length as a difference of positions that are out of order; off-by-one loops passing negative remainders.","solutions":["Clamp or validate len >= 0 before calling read; treat negative as zero or an error in your code","Check for int/long overflow when converting unsigned metadata sizes to signed Java types","Fix computation order so the read length is end - start with start <= end","Catch IndexOutOfBoundsException at the reader boundary and surface which length was computed"],"exampleFix":"// before\nint len = (int) (endPos - startPos); // may be negative or overflow\nstream.read(buf, 0, len);\n// after\nint len = (int) Math.max(0, endPos - startPos);\nif (len > 0) {\n  stream.read(buf, 0, len);\n}","handlingStrategy":"validation","validationCode":"if (len < 0) {\n  throw new IllegalArgumentException(\"Negative read length \" + len + \" (likely unsigned overflow)\");\n}\nstream.read(buf, off, len);","typeGuard":"int safeLen(long computedLen) {\n  return (int) Math.min(Math.max(computedLen, 0L), Integer.MAX_VALUE);\n}","tryCatchPattern":"try {\n  stream.read(buf, off, len);\n} catch (IndexOutOfBoundsException e) {\n  throw new IOException(\"Bad read length; check unsigned size handling\", e);\n}","preventionTips":["Clamp computed lengths to >= 0 before reading","Use unsigned-safe conversions for metadata sizes read into signed ints","Ensure position differences are taken in the correct order"],"tags":["io","invalid-argument","index-out-of-bounds","overflow"],"backgroundTag":"index-out-of-bounds","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"}