ReactiveX/RxJava · warning · UnsupportedOperationException
Read only iterator
Error message
Read only iterator
What it means
Thrown by Iterator.remove() on the iterator from Observable.blockingMostRecent(). The iterator replays the most recently emitted Notification (value, completion, or error) and is a read-only view, so remove() always throws UnsupportedOperationException("Read only iterator"). There is no underlying collection to mutate.
Source
Thrown at src/main/java/io/reactivex/rxjava4/internal/operators/observable/BlockingObservableMostRecent.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; this iterator is read-only.
- Filter the source upstream with Observable.filter(...) to exclude items before blocking iteration.
- Maintain your own mutable collection of retained items instead of mutating the iterator.
- Delegate through a no-op remove() wrapper if a dependency requires the method.
Example fix
// before
Iterator<T> it = observable.blockingMostRecent(initial).iterator();
while (it.hasNext()) { T v = it.next(); if (drop(v)) it.remove(); }
// after
Iterator<T> it = observable.blockingMostRecent(initial).iterator();
List<T> kept = new ArrayList<>();
while (it.hasNext()) { T v = it.next(); if (!drop(v)) kept.add(v); } Defensive patterns
Strategy: validation
Validate before calling
// Read-only iterator: never call remove().
Iterator<T> it = observable.blockingMostRecent(initial).iterator();
while (it.hasNext()) {
T v = it.next();
// process v; it.remove() is unsupported
} Prevention
- Treat blockingMostRecent() iterators as unmodifiable views.
- Filter upstream with Observable.filter(...) to exclude items.
- Maintain your own mutable collection of retained items.
- Use a no-op remove() forwarder if a dependency mandates remove().
When it happens
Trigger: Calling it.remove() on the iterator from observable.blockingMostRecent(initial).iterator(); a generic consumer that invokes remove() during drain; ported imperative loop with a remove() step.
Common situations: Legacy collection-processing code that paired next() with remove(); a utility library that calls remove() on any iterator; misreading blockingMostRecent() as a queue you can shrink.
Related errors
AI-assisted analysis of ReactiveX/RxJava@a8ab535614 (2026-08-13).
Data as JSON: /api/errors/ef87d03e868d4d70.
Report an issue: GitHub.