apache/pulsar · error · IllegalArgumentException
Unsupported LongBitmap type: <other.getClass()>
Error message
Unsupported LongBitmap type: <other.getClass()>
What it means
ConcurrentRoaringBitmap.or(LongBitmap) only supports bitwise-OR with another ConcurrentRoaringBitmap; passing any other LongBitmap implementation throws IllegalArgumentException. Locking order for the merge is only defined between instances of this class.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/ConcurrentRoaringBitmap.java:298
// ensures rank(0x100000000L) counts all values in the uint32 range.
if (value > UINT32_SIZE) {
value = UINT32_SIZE;
}
long stamp = lock.readLock();
try {
return bitmap.rank((int) (value - 1));
} finally {
lock.unlockRead(stamp);
}
}
@Override
public void or(LongBitmap other) {
if (other == this) {
return;
}
if (!(other instanceof ConcurrentRoaringBitmap)) {
throw new IllegalArgumentException("Unsupported LongBitmap type: " + other.getClass());
}
ConcurrentRoaringBitmap that = (ConcurrentRoaringBitmap) other;
// Acquire this.writeLock + that.readLock in identityHashCode order so concurrent
// A.or(B) and B.or(A) don't deadlock. Fall back to inner bitmap identity on collision.
boolean thisFirst;
int outerCmp = Integer.compare(
System.identityHashCode(this), System.identityHashCode(that));
if (outerCmp != 0) {
thisFirst = outerCmp < 0;
} else {
thisFirst = System.identityHashCode(this.bitmap) < System.identityHashCode(that.bitmap);
}
if (thisFirst) {
long thisStamp = this.lock.writeLock();
try {
long thatStamp = that.lock.readLock();View on GitHub (pinned to 820761864e)
Solutions
- Ensure both operands are ConcurrentRoaringBitmap instances; copy foreign bitmaps via deserialization into a ConcurrentRoaringBitmap first
- Guard with `other instanceof ConcurrentRoaringBitmap` before calling or()
- Standardize on one LongBitmap implementation across the codebase
Example fix
// before
bitmap.or(foreignBitmap); // throws
// after
if (foreignBitmap instanceof ConcurrentRoaringBitmap) {
bitmap.or(foreignBitmap);
} else {
ConcurrentRoaringBitmap converted =
ConcurrentRoaringBitmap.deserialize(foreignBitmap.serialize());
bitmap.or(converted);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!(other instanceof ConcurrentRoaringBitmap)) {
other = ConcurrentRoaringBitmap.deserialize(other.serialize());
}
bm.or(other); Type guard
static boolean isConcurrentRoaring(LongBitmap b) {
return b instanceof ConcurrentRoaringBitmap;
} Try / catch
try {
bm.or(other);
} catch (IllegalArgumentException e) {
throw new IllegalStateException("Mixing LongBitmap implementations: " + e.getMessage(), e);
} Prevention
- Use a single LongBitmap implementation project-wide
- Convert foreign bitmaps at module boundaries
- Check method contracts before passing interface-typed arguments
When it happens
Trigger: Calling bitmap.or(otherBitmap) where otherBitmap is a foreign LongBitmap implementation (custom class or a different library's roaring bitmap wrapper).
Common situations: Mixing bitmap implementations across plugins/modules, or after a library swap where a different LongBitmap impl is returned by an API.
Related errors
- configuredService should not be an instance of SystemTopicBa
- Segment not found
- Both segments must be active
- Segments are not adjacent: ${hashRange1} and ${hashRange2}
- Cannot rebucket non-active segment: ${segmentId}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/137f5321e772ee1f.
Report an issue: GitHub.