apache/pulsar · error · NegativeArraySizeException
nbits < 0: <nbits>
Error message
nbits < 0: <nbits>
What it means
BitSetRecyclable(int nbits) mirrors java.util.BitSet's constructor: a negative initial bit count is rejected with NegativeArraySizeException("nbits < 0: " + nbits) before any words are allocated. The library throws this to fail fast rather than letting an internal long[] allocation fail confusingly, since a negative length array is impossible. A size of 0 is explicitly allowed.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/BitSetRecyclable.java:128
*/
public BitSetRecyclable() {
initWords(BITS_PER_WORD);
sizeIsSticky = false;
}
/**
* Creates a bit set whose initial size is large enough to explicitly
* represent bits with indices in the range {@code 0} through
* {@code nbits-1}. All bits are initially {@code false}.
*
* @param nbits the initial size of the bit set
* @throws NegativeArraySizeException if the specified initial size
* is negative
*/
public BitSetRecyclable(int nbits) {
// nbits can't be negative; size 0 is OK
if (nbits < 0)
throw new NegativeArraySizeException("nbits < 0: " + nbits);
initWords(nbits);
sizeIsSticky = true;
}
private void initWords(int nbits) {
words = new long[wordIndex(nbits-1) + 1];
}
/**
* Creates a bit set using words as the internal representation.
* The last word (if there is one) must be non-zero.
*/
private BitSetRecyclable(long[] words) {
this.words = words;
this.wordsInUse = words.length;
checkInvariants();
}View on GitHub (pinned to 820761864e)
Solutions
- Clamp or reject before construction: if (n < 0) n = 0; or throw a domain-specific error naming the source of n.
- If n is a sentinel for 'not set', branch on it explicitly instead of passing it to the constructor.
- Check the arithmetic producing n for overflow (use Math.addExact/Math.multiplyExact) and for integer division/cast errors.
- If the value comes from deserialized data, validate the length header against remaining bytes before trusting it.
Example fix
// before int nbits = header.getLength(); // may be -1 sentinel BitSetRecyclable set = new BitSetRecyclable(nbits); // after int nbits = header.getLength(); if (nbits < 0) nbits = 0; // treat sentinel/invalid as empty bit set BitSetRecyclable set = new BitSetRecyclable(nbits);
Defensive patterns
Strategy: validation
Validate before calling
static BitSetRecyclable newBitSet(int nbits) {
if (nbits < 0) {
throw new IllegalArgumentException("nbits must be >= 0, got " + nbits + " (check sentinel/overflow)");
}
return new BitSetRecyclable(nbits);
} Type guard
static boolean isValidBitSetSize(int n) { return n >= 0; } Try / catch
try {
BitSetRecyclable set = new BitSetRecyclable(nbits);
} catch (NegativeArraySizeException e) {
log.warn("Non-positive bit-set size requested: {}", e.getMessage());
BitSetRecyclable set = new BitSetRecyclable(0); // or rethrow as a data-corruption error
} Prevention
- Handle -1-style sentinels explicitly before passing values to the constructor.
- Use Math.addExact/Math.multiplyExact for size arithmetic to catch overflow.
- Validate length fields from deserialized/wire data before using them as sizes.
- Write a unit test asserting the constructor rejects negative sizes so regressions surface early.
When it happens
Trigger: Constructing new BitSetRecyclable(n) where n < 0, typically when n comes from a computation such as (numBits/8 + 1)*8 gone wrong, an unchecked cast, a corrupted length header, or a recycled/recyclable value that was reset to -1 as a sentinel and passed straight to the constructor.
Common situations: Deserializing a payload whose declared bit-set length is negative (corrupt or hostile data); arithmetic overflow wrapping a large positive count to negative; calling the constructor inside a recycling path where a sentinel value (-1 meaning 'uninitialized') leaks through; off-by-one/negative results from subtracting sizes.
Related errors
- fromIndex < 0: <fromIndex>
- toIndex < 0: <toIndex>
- fromIndex: <fromIndex> > toIndex: <toIndex>
- bitIndex < 0: <bitIndex>
- fromIndex < -1: <fromIndex>
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/fc118165231807e5.
Report an issue: GitHub.