apache/pulsar · error · IndexOutOfBoundsException
fromIndex < 0: <fromIndex>
Error message
fromIndex < 0: <fromIndex>
What it means
BitSetRecyclable.checkRange validates a [fromIndex, toIndex) bit-index range before flip/set/clear/get operate on it, and throws IndexOutOfBoundsException("fromIndex < 0: " + fromIndex) when fromIndex is negative. The check mirrors java.util.BitSet so callers get the same fail-fast semantics; toIndex and ordering are checked separately. The exception propagates out of whichever public method (flip, set, clear, get) invoked checkRange.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/BitSetRecyclable.java:339
* temporarily violating the invariants. The caller must
* restore the invariants before returning to the user,
* 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);View on GitHub (pinned to 820761864e)
Solutions
- Validate the index before the call: if (idx < 0) skip/handle, or clamp with Math.max(0, idx) when that matches your intent.
- If the index comes from a lookup that can return -1, check for the sentinel before using it as a bit position.
- For range calls, ensure fromIndex >= 0 and fromIndex <= toIndex (ordering violations raise a different message from the same method).
- If the position is derived from parsed data, validate it against the expected bit-set size before mutating.
Example fix
// before
int bit = findBit(key); // returns -1 when absent
bitSet.set(bit);
// after
int bit = findBit(key);
if (bit >= 0) {
bitSet.set(bit);
} Defensive patterns
Strategy: validation
Validate before calling
static void requireValidBitIndex(int idx) {
if (idx < 0) throw new IllegalArgumentException("bit index must be >= 0, got " + idx + " (lookup miss?)");
} Type guard
static boolean isValidBitIndex(int idx) { return idx >= 0; } Try / catch
try {
bitSet.set(index);
} catch (IndexOutOfBoundsException e) {
log.warn("Ignoring invalid bit index {} ({} )", index, e.getMessage());
// skip or convert to a domain error depending on caller contract
} Prevention
- Always check indexOf-style results for -1 before using them as bit positions.
- Validate bit positions parsed from external data against expected maximum size.
- Use java.util.OptionalInt (or isPresent checks) for lookups so a miss can't silently become an index.
- Add a guard method like requireValidBitIndex around all bitSet mutations in shared code.
When it happens
Trigger: Calling flip(int), set(int), clear(int) or get(int) with a negative single index (fromIndex == toIndex == the negative value), or range variants flip/set/clear/get(fromIndex, toIndex) with fromIndex < 0 — e.g. bit indices derived from uninitialized values, decoded lengths, or arithmetic on empty data.
Common situations: Using a sentinel -1 ('bit not found') directly as a bit index from indexOf-style lookups; decoding a bit position from wire data that was truncated or corrupted; off-by-one arithmetic such as (position - offset) where offset > position; iterating from lastIndex computed as length-1 when length is 0.
Related errors
- toIndex < 0: <toIndex>
- 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/f78a8ae343a3e84e.
Report an issue: GitHub.