ReactiveX/RxJava · warning · UnsupportedOperationException
Read only iterator
Error message
Read only iterator
What it means
Thrown by the Iterator returned from Flowable.blockingMostRecent() when its remove() method is called. Blocking operators expose the live stream as a read-only Iterator over the most-recently-emitted value, so mutation via remove() is forbidden by design and always throws UnsupportedOperationException. The iterator reflects a push-based source, so there is no backing collection to remove from.
Source
Thrown at src/main/java/io/reactivex/rxjava4/internal/operators/flowable/BlockingFlowableMostRecent.java:115
if (buf == null) {
buf = value;
}
if (NotificationLite.isComplete(buf)) {
throw new NoSuchElementException();
}
if (NotificationLite.isError(buf)) {
throw ExceptionHelper.wrapOrThrow(NotificationLite.getError(buf));
}
return NotificationLite.getValue(buf);
}
finally {
buf = null;
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Read only iterator");
}
}
}
}
View on GitHub (pinned to a8ab535614)
Solutions
- Remove the it.remove() call from your loop; blocking RxJava iterators are read-only views and never support removal.
- If you need to filter, apply Flowable.filter(...) before blockingMostRecent() instead of mutating the iterator.
- If a generic helper mandates remove(), wrap the iterator with your own delegating Iterator whose remove() is a no-op.
- Collect results into a separate mutable list rather than trying to mutate the source iterator.
Example fix
// before
Iterator<T> it = flowable.blockingMostRecent(initial).iterator();
while (it.hasNext()) { it.next(); it.remove(); }
// after
Iterator<T> it = flowable.blockingMostRecent(initial).iterator();
while (it.hasNext()) { T v = it.next(); /* use v, never remove() */ } Defensive patterns
Strategy: validation
Validate before calling
// Never call remove() on blocking RxJava iterators.
// Before your loop, confirm the iterator is read-only by design (no runtime check needed);
// simply omit it.remove().
Iterator<T> it = flowable.blockingMostRecent(initial).iterator();
while (it.hasNext()) {
T v = it.next();
// process v; do NOT call it.remove()
} Prevention
- Treat all blocking RxJava iterators as unmodifiable views; never call remove().
- Filter upstream with Flowable.filter(...) rather than mutating the iterator.
- If a generic helper calls remove(), wrap the iterator in a forwarder with a no-op remove().
- Collect results into your own mutable collection instead of mutating the source iterator.
When it happens
Trigger: Calling Iterator.remove() on the iterator obtained from Flowable.blockingMostRecent(initialValue).next() iteration loop; using a generic utility that defensively invokes remove() on any iterator it consumes; Java for-each is fine, but explicit it.remove() after it.next() triggers it.
Common situations: Migrating imperative collection-processing code (that used List.remove() semantics) onto a blocking RxJava iterator; helper libraries that call remove() as part of cleanup; copy-paste of a loop template that included it.remove().
Related errors
AI-assisted analysis of ReactiveX/RxJava@a8ab535614 (2026-08-13).
Data as JSON: /api/errors/8a4708cdfc6913fa.
Report an issue: GitHub.