ReactiveX/RxJava · warning · NoSuchElementException
No more elements
Error message
No more elements
What it means
Thrown by Iterator.next() from Flowable.blockingNext() when the upstream has completed and there is no further item to deliver. It signals a normal terminal condition of the blocking iterator: next() was called after the source Flowable signalled onComplete (or after the last buffered Notification was consumed and hasNext() is now false).
Source
Thrown at src/main/java/io/reactivex/rxjava4/internal/operators/flowable/BlockingFlowableNext.java:122
} catch (InterruptedException e) {
subscriber.dispose();
error = e;
throw ExceptionHelper.wrapOrThrow(e);
}
}
@Override
public T next() {
if (error != null) {
// If any error has already been thrown, throw it again.
throw ExceptionHelper.wrapOrThrow(error);
}
if (hasNext()) {
isNextConsumed = true;
return next;
}
else {
throw new NoSuchElementException("No more elements");
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Read only iterator");
}
}
static final class NextSubscriber<T> extends DisposableSubscriber<Notification<T>> {
private final BlockingQueue<Notification<T>> buf = new ArrayBlockingQueue<>(1);
final AtomicInteger waiting = new AtomicInteger();
@Override
public void onComplete() {
// ignore
}
View on GitHub (pinned to a8ab535614)
Solutions
- Always guard next() with hasNext(): while (it.hasNext()) { T v = it.next(); ... }
- Verify the upstream Flowable emits the expected count (use test() assertions) before relying on blocking iteration.
- If an empty result is legitimate, catch NoSuchElementException and supply a default instead of treating it as a failure.
- Add an isEmpty check via Flowable.isEmpty().blockingGet() before iterating if a non-empty contract is required.
Example fix
// before
Iterator<T> it = flowable.blockingNext().iterator();
T first = it.next(); // throws if source empty
// after
Iterator<T> it = flowable.blockingNext().iterator();
if (!it.hasNext()) { return defaultValue; }
T first = it.next(); Defensive patterns
Strategy: try-catch
Validate before calling
// Validate non-empty before consuming the blocking next-iterator.
boolean nonEmpty = flowable.isEmpty().blockingGet(); // false => has at least one
Iterator<T> it = flowable.blockingNext().iterator();
if (!it.hasNext()) { /* source is empty/complete */ } Try / catch
Iterator<T> it = flowable.blockingNext().iterator();
T value;
if (it.hasNext()) {
value = it.next();
} else {
// handle terminal/empty state
value = defaultValue;
}
// Alternatively, only if a default cannot be structured in:
try {
while (it.hasNext()) { T v = it.next(); /* consume */ }
} catch (NoSuchElementException e) {
// safe: loop is hasNext-guarded, but guard against stray next() calls
} Prevention
- Always guard Iterator.next() with hasNext() and stop when it returns false.
- Use Flowable.isEmpty().blockingGet() to pre-check a non-empty contract.
- Assert expected emission counts with test() before relying on blocking iteration.
- Prefer a default-supplying accessor when an empty source is legitimate.
When it happens
Trigger: Calling next() without guarding hasNext() after the source completes; a loop that assumes N items but the source emitted fewer; the upstream completes immediately (e.g. Flowable.empty()) and next() is invoked once.
Common situations: Parsing/flattening a finite stream via blockingNext() and miscounting expected elements; an upstream that completes early due to a filter that removes all elements; off-by-one in a manual index counter driving next() calls.
Related errors
AI-assisted analysis of ReactiveX/RxJava@a8ab535614 (2026-08-13).
Data as JSON: /api/errors/81777e6311817a5c.
Report an issue: GitHub.