apache/druid · error · NoSuchElementException
No more frames to produce. Call `hasNext()` before calling…
Error message
No more frames to produce. Call `hasNext()` before calling `next()`
What it means
This NoSuchElementException is thrown by ScanResultValueFramesIterable's iterator when next() is called after all frames have been exhausted, without first checking hasNext(). The library enforces the standard Java Iterator contract: callers must poll hasNext() before each next() call. It is a caller-side protocol violation, not an internal fault.
Solutions
- Guard every next() call with if (iterator.hasNext()) or use a for-each loop
- Stop iterating as soon as hasNext() returns false; do not call next() again after exhaustion
- If buffering frames, track remaining count and avoid extra next() calls
Example fix
// before
while (true) {
FrameSignaturePair frame = iterator.next();
process(frame);
}
// after
while (iterator.hasNext()) {
FrameSignaturePair frame = iterator.next();
process(frame);
} Defensive patterns
Strategy: type-guard
Validate before calling
if (it.hasNext()) { FrameSignaturePair f = it.next(); ... } Type guard
boolean safeNext(Iterator<FrameSignaturePair> it) { return it.hasNext(); } // check before any next() Try / catch
try { f = it.next(); } catch (NoSuchElementException e) { /* iterator exhausted: stop iterating */ } Prevention
- Always use for-each or while(hasNext()) loops over frame iterators
- Never call next() twice per element
- Treat iterators as one-shot; re-obtain from the iterable if you need to re-iterate
When it happens
Trigger: Calling iterator.next() repeatedly on a scan-query frame iterator without calling hasNext(); iterating past the last frame in a while(true) loop; using an iterator after draining all frames in custom result-handling code.
Common situations: Custom hooks or extension code that consumes scan frames manually instead of a standard for-each loop; porting code that assumed next() would return null at end of stream; wrapping the iterator in an adapter that forgets the hasNext() check.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- 08001
- A batch appenderator was already created for this peon's…
- A-Not-B requires at least 1 sketch
- A realtime appenderator was already created for this peon's…
- AggregatorFactoryNotMergeableException
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/b461f809c73af82a.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/query/scan/ScanResultValueFramesIterable.java:223
closer.register(resultSequenceIterator);
// Makes sure that we run through all the empty scan result values at the beginning and are pointing to a valid
// row
populateCursor();
}
@Override
public boolean hasNext()
{
return !done();
}
@Override
public FrameSignaturePair next()
{
if (!hasNext()) {
throw new NoSuchElementException("No more frames to produce. Call `hasNext()` before calling `next()`");
}
// It would ensure that the cursor and the currentRowSignature is populated properly before we
// start all the processing
populateCursor();
boolean firstRowWritten = false;
final FrameWriterFactory frameWriterFactory = FrameWriters.makeColumnBasedFrameWriterFactory(
memoryAllocatorFactory,
currentOutputRowSignature,
Collections.emptyList()
);
final Frame frame;
try (final FrameWriter frameWriter = frameWriterFactory.newFrameWriter(
new SettableCursorColumnSelectorFactory(() -> currentCursor, currentInputRowSignature))) {
while (populateCursor()) { // Do till we don't have any more rows, or the next row isn't compatible with the current row
if (!frameWriter.addSelection()) { // Add the cursor's row to the frame, till the frame is full
break;View on GitHub (pinned to 9b90983fd2)