apache/druid · error · NoSuchElementException

NoSuchElementException

Error message

NoSuchElementException

What it means

Java standard NoSuchElementException thrown by AzureCloudBlobIterator.next() when the iterator has no more blob items (currentBlobItem == null), violating the Iterator contract by calling next() past the end instead of using hasNext().

Source

Thrown at extensions-core/azure-extensions/src/main/java/org/apache/druid/storage/azure/AzureCloudBlobIterator.java:88

    if (prefixesIterator.hasNext()) {
      prepareNextRequest();
      fetchNextBatch();
      advanceBlobItem();
    }
  }

  @Override
  public boolean hasNext()
  {
    return currentBlobItem != null;
  }

  @Override
  public CloudBlobHolder next()
  {
    if (currentBlobItem == null) {
      throw new NoSuchElementException();
    }

    final CloudBlobHolder retVal = currentBlobItem;
    advanceBlobItem();
    return retVal;
  }

  private void prepareNextRequest()
  {
    URI currentUri = prefixesIterator.next();

    if (currentUri.getScheme().equals(AzureStorageAccountInputSource.SCHEME)) {
      CloudObjectLocation cloudObjectLocation = new CloudObjectLocation(currentUri);
      Pair<String, String> containerInfo = AzureStorageAccountInputSource.getContainerAndPathFromObjectLocation(cloudObjectLocation);
      currentStorageAccount = cloudObjectLocation.getBucket();
      currentContainer = containerInfo.lhs;
      currentPrefix = containerInfo.rhs;
    } else {

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Always guard with hasNext() before calling next()
  2. Handle the empty-prefix case explicitly before iterating
  3. Check the prefix/container name if you expected results — an empty list usually means a wrong path
  4. Ensure a single thread consumes the iterator; it is not thread-safe

Example fix

// before
CloudBlobHolder holder = iterator.next();
// after
if (iterator.hasNext()) {
  CloudBlobHolder holder = iterator.next();
} else {
  // handle empty result set
}
Defensive patterns

Strategy: type-guard

Validate before calling

// check for results before iterating
if (!iterator.hasNext()) {
  LOG.info("No blobs under prefix");
  return Collections.emptyList();
}

Type guard

boolean hasCurrent(Iterator<CloudBlobHolder> it) {
  return it != null && it.hasNext();
}

Try / catch

try {
  CloudBlobHolder holder = iterator.next();
} catch (NoSuchElementException e) {
  LOG.warn("Iteration advanced past end; check hasNext() usage", e);
}

Prevention

When it happens

Trigger: Calling next() after hasNext() returned false, or calling next() before the first successful fetchNextBatch populated currentBlobItem — e.g., an empty prefix with no blobs, or a loop that ignores hasNext().

Common situations: Listing an Azure container prefix that matches zero blobs; code that assumes at least one result; off-by-one loops iterating exactly blobCount+1 times; concurrent iteration/modification of the underlying batch list.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/f92e484dfdddfb1e. Report an issue: GitHub.