apache/beam · error · IllegalArgumentException
length is negative:
Error message
length is negative:
What it means
SubstringByteArrayOutputStream.toString validates that the requested length is non-negative before copying bytes out of the buffer. A negative length indicates the caller computed the record size incorrectly (e.g. end position before start position) and the library fails fast with a clear message instead of a cryptic exception from lower-level array copies.
Source
Thrown at sdks/java/core/src/main/java/org/apache/beam/sdk/io/TextSource.java:480
*
* <pre>{@code
* ByteArrayOutputStream out = ...;
* byte[] buffer = out.toByteArray(); // 1st-copy
* String s = new String(buffer, offset, length); // 2nd-copy
* }</pre>
*/
static class SubstringByteArrayOutputStream extends ByteArrayOutputStream {
public String toString(int offset, int length, Charset charset) {
if (offset < 0) {
throw new IllegalArgumentException("offset is negative: " + offset);
}
if (offset > count) {
throw new IllegalArgumentException(
"offset exceeds the buffer limit. offset: " + offset + ", limit: " + count);
}
if (length < 0) {
throw new IllegalArgumentException("length is negative: " + length);
}
if (offset + length > count) {
throw new IllegalArgumentException(
"offset + length exceeds the buffer limit. offset: "
+ offset
+ ", length: "
+ length
+ ", limit: "
+ count);
}
return new String(buf, offset, length, charset);
}
}
/**
* See <aView on GitHub (pinned to 12126d8942)
Solutions
- Check delimiter search results for -1 before computing length; handle not-found explicitly.
- Validate length >= 0 in the caller (e.g. Preconditions.checkArgument(length >= 0)).
- Fix the ordering of start/end computation so end >= start always holds for a found record.
Example fix
// before int len = endIdx - startIdx; // endIdx can be -1 String s = buffer.toString(startIdx, len, UTF_8); // after checkState(endIdx >= 0, "record delimiter not found"); int len = endIdx - startIdx; String s = buffer.toString(startIdx, len, UTF_8);
Defensive patterns
Strategy: validation
Validate before calling
checkState(endIdx >= 0, "record delimiter not found"); checkArgument(endIdx - startIdx >= 0, "record length must be non-negative");
Try / catch
try {
String s = buffer.toString(startIdx, len, UTF_8);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("invalid record length: " + e.getMessage(), e);
} Prevention
- Always check indexOf-style results for -1 before computing lengths.
- Compute length as end - start only when end >= start is guaranteed.
- Beware of int overflow when lengths derive from unsigned data.
When it happens
Trigger: Calling toString(offset, length, charset) with length < 0 — usually when length = end - start and end < start because record delimiters were searched in the wrong order or the delimiter was not found and -1 was used.
Common situations: Custom TextSource subclasses computing record lengths from indexOf results that returned -1; arithmetic on unsigned values stored in signed ints that overflowed; tests exercising invalid ranges.
Related errors
- offset is negative:
- offset exceeds the buffer limit. offset: , limit:
- offset + length exceeds the buffer limit. offset: , length:
- Failed closing channel to %s
- Error determining if %s allows dynamic splitting
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/57346a86940b39b0.
Report an issue: GitHub.