apache/pulsar · error · UnsupportedOperationException
stream is not supported
Error message
stream is not supported
What it means
ConcurrentBitSet.stream() is explicitly unsupported: the class overrides IntStream stream() only to throw UnsupportedOperationException("stream is not supported"), because materializing a stream from a lock-striped concurrent bit set cannot provide the snapshot semantics callers expect. The compiler will accept the call; the failure happens only at runtime.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/ConcurrentBitSet.java:430
String str = super.toString();
if (!rwLock.validate(stamp)) {
// Fallback to read lock
stamp = rwLock.readLock();
try {
str = super.toString();
} finally {
rwLock.unlockRead(stamp);
}
}
return str;
}
/**
* This operation is not supported on {@code ConcurrentBitSet}.
*/
@Override
public IntStream stream() {
throw new UnsupportedOperationException("stream is not supported");
}
public boolean equals(final Object o) {
if (o == this) {
return true;
}
if (!(o instanceof ConcurrentBitSet)) {
return false;
}
long stamp = rwLock.tryOptimisticRead();
boolean isEqual = super.equals(o);
if (!rwLock.validate(stamp)) {
// Fallback to read lock
stamp = rwLock.readLock();
try {
isEqual = super.equals(o);
} finally {
rwLock.unlockRead(stamp);View on GitHub (pinned to 820761864e)
Solutions
- Replace stream() with index-based iteration: loop i from 0 while calling nextSetBit(i) semantics if available, or use the word/index API
- Use the underlying get()/nextClearBit-style iteration appropriate to ConcurrentBitSet's API
- If a snapshot is needed, copy bits into a plain BitSet or int list under the caller's synchronization, then stream that
- Audit generic code paths for UnsupportedOperationException when adopting ConcurrentBitSet
Example fix
// before
IntStream indices = concurrentBitSet.stream();
// after
List<Integer> indices = new ArrayList<>();
for (int i = 0; i < concurrentBitSet.length(); i++) {
if (concurrentBitSet.get(i)) indices.add(i);
} Defensive patterns
Strategy: try-catch
Validate before calling
// ConcurrentBitSet does not support stream(); iterate instead
List<Integer> setBits = new ArrayList<>();
for (int i = 0; i < concurrentBitSet.length(); i++) {
if (concurrentBitSet.get(i)) setBits.add(i);
} Type guard
static boolean supportsStream(Object bitSet) { return !(bitSet instanceof ConcurrentBitSet); } Try / catch
try {
stream = bitSet.stream();
} catch (UnsupportedOperationException e) {
// fall back to index-based iteration
stream = indexBasedStream(bitSet);
} Prevention
- Never call stream() on ConcurrentBitSet; its Javadoc marks it unsupported
- When swapping in ConcurrentBitSet, audit all BitSet operations used
- Prefer index-based iteration (get/nextSetBit-style) for concurrent sets
- Keep a shared utility that iterates any BitSet-like type safely
When it happens
Trigger: Calling stream() on a ConcurrentBitSet (not BitSetRecyclable) — e.g. generic code written against a BitSet-like abstraction, or refactoring code that used BitSetRecyclable/plain BitSet to use ConcurrentBitSet and kept the stream-based iteration.
Common situations: Switching a data structure to ConcurrentBitSet for thread safety without auditing all operations; library code that streams any BitSet; collecting acknowledged indices for logging/stats.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Expire message by timestamp is not supported for non-persist
- Expire message by position is not supported for non-persiste
- PublishTxnMessage is not supported by non-persistent topic
- Receiver queue size can't be changed in ZeroQueueConsumerImp
- nbits < 0: <nbits>
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/683bb311a80a8e49.
Report an issue: GitHub.