apache/pulsar · error · IndexOutOfBoundsException
toIndex < 0: <toIndex>
Error message
toIndex < 0: <toIndex>
What it means
In the same checkRange method, BitSetRecyclable throws IndexOutOfBoundsException("toIndex < 0: " + toIndex) when the upper bound of a bit range is negative, after the fromIndex check. Since fromIndex <= toIndex is enforced later, a negative toIndex almost always means both bounds are negative, but it is checked independently to give a precise message. flip/set/clear/get range variants all funnel through this guard.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/BitSetRecyclable.java:341
* possibly using recalculateWordsInUse().
* @param wordIndex the index to be accommodated.
*/
private void expandTo(int wordIndex) {
int wordsRequired = wordIndex+1;
if (wordsInUse < wordsRequired) {
ensureCapacity(wordsRequired);
wordsInUse = wordsRequired;
}
}
/**
* Checks that fromIndex ... toIndex is a valid range of bit indices.
*/
private static void checkRange(int fromIndex, int toIndex) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex < 0: " + fromIndex);
if (toIndex < 0)
throw new IndexOutOfBoundsException("toIndex < 0: " + toIndex);
if (fromIndex > toIndex)
throw new IndexOutOfBoundsException("fromIndex: " + fromIndex +
" > toIndex: " + toIndex);
}
/**
* Sets the bit at the specified index to the complement of its
* current value.
*
* @param bitIndex the index of the bit to flip
* @throws IndexOutOfBoundsException if the specified index is negative
* @since 1.4
*/
public void flip(int bitIndex) {
if (bitIndex < 0)
throw new IndexOutOfBoundsException("bitIndex < 0: " + bitIndex);
int wordIndex = wordIndex(bitIndex);View on GitHub (pinned to 820761864e)
Solutions
- Validate bounds before the call: if (toIndex < 0) return/handle, or normalize empty ranges to (0, 0).
- For inclusive-style bounds converted to exclusive (toIndex = end + 1), ensure the conversion handles end = -1 (empty) by skipping the operation entirely.
- Check the arithmetic producing toIndex (additions with negative lengths, size()-1 on empty collections).
- If bounds come from external data, validate start >= 0 and end >= start against the actual bit-set capacity before calling.
Example fix
// before
int end = values.size() - 1; // values empty -> end = -1
bitSet.set(0, end);
// after
int end = values.size() - 1;
if (end >= 0) {
bitSet.set(0, end);
} Defensive patterns
Strategy: validation
Validate before calling
static void requireValidRange(int fromIndex, int toIndex) {
if (fromIndex < 0 || toIndex < 0 || fromIndex > toIndex)
throw new IllegalArgumentException("invalid range [" + fromIndex + ", " + toIndex + ")");
} Type guard
static boolean isValidRange(int from, int to) { return from >= 0 && to >= from; } Try / catch
try {
bitSet.set(from, to);
} catch (IndexOutOfBoundsException e) {
log.warn("Skipping invalid bit range [{}, {}): {}", from, to, e.getMessage());
// treat as empty range or escalate to a data-corruption error
} Prevention
- Compute exclusive upper bounds defensively: skip the operation when the range is empty (toIndex <= fromIndex <= 0).
- Never derive toIndex as size()-1 for inclusive-style APIs; convert explicitly to exclusive bounds with an empty-case branch.
- Validate (start, length) pairs from wire/serialized data before constructing ranges.
- Centralize range construction in one helper that runs the same checks as checkRange.
When it happens
Trigger: Calling set(fromIndex, toIndex), clear(fromIndex, toIndex), flip(fromIndex, toIndex) or get(fromIndex, toIndex) with toIndex < 0 — e.g. toIndex computed as length + delta where delta is negative, or both indices taken from an uninitialized/empty result like (start, end) of an empty span.
Common situations: Slicing ranges from deserialized data where the length field was 0 or negative, producing toIndex = start + length < 0; passing (0, list.size() - 1) style bounds when the collection is empty (toIndex = -1); copying range logic between 0-based and 1-based systems.
Related errors
- fromIndex < 0: <fromIndex>
- fromIndex: <fromIndex> > toIndex: <toIndex>
- bitIndex < 0: <bitIndex>
- fromIndex < -1: <fromIndex>
- nbits < 0: <nbits>
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/e67a1cdf0bc29f84.
Report an issue: GitHub.