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

  1. Guard every next() call with if (iterator.hasNext()) or use a for-each loop
  2. Stop iterating as soon as hasNext() returns false; do not call next() again after exhaustion
  3. 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

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


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)