{"record":{"id":"f92e484dfdddfb1e","repo":"apache/druid","slug":"nosuchelementexception","errorCode":null,"errorMessage":"NoSuchElementException","messagePattern":"NoSuchElementException","errorType":"exception","errorClass":"NoSuchElementException","httpStatus":null,"severity":"error","filePath":"extensions-core/azure-extensions/src/main/java/org/apache/druid/storage/azure/AzureCloudBlobIterator.java","lineNumber":88,"sourceCode":"\n    if (prefixesIterator.hasNext()) {\n      prepareNextRequest();\n      fetchNextBatch();\n      advanceBlobItem();\n    }\n  }\n\n  @Override\n  public boolean hasNext()\n  {\n    return currentBlobItem != null;\n  }\n\n  @Override\n  public CloudBlobHolder next()\n  {\n    if (currentBlobItem == null) {\n      throw new NoSuchElementException();\n    }\n\n    final CloudBlobHolder retVal = currentBlobItem;\n    advanceBlobItem();\n    return retVal;\n  }\n\n  private void prepareNextRequest()\n  {\n    URI currentUri = prefixesIterator.next();\n\n    if (currentUri.getScheme().equals(AzureStorageAccountInputSource.SCHEME)) {\n      CloudObjectLocation cloudObjectLocation = new CloudObjectLocation(currentUri);\n      Pair<String, String> containerInfo = AzureStorageAccountInputSource.getContainerAndPathFromObjectLocation(cloudObjectLocation);\n      currentStorageAccount = cloudObjectLocation.getBucket();\n      currentContainer = containerInfo.lhs;\n      currentPrefix = containerInfo.rhs;\n    } else {","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/azure-extensions/src/main/java/org/apache/druid/storage/azure/AzureCloudBlobIterator.java#L70-L106","documentation":"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().","triggerScenarios":"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().","commonSituations":"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.","solutions":["Always guard with hasNext() before calling next()","Handle the empty-prefix case explicitly before iterating","Check the prefix/container name if you expected results — an empty list usually means a wrong path","Ensure a single thread consumes the iterator; it is not thread-safe"],"exampleFix":"// before\nCloudBlobHolder holder = iterator.next();\n// after\nif (iterator.hasNext()) {\n  CloudBlobHolder holder = iterator.next();\n} else {\n  // handle empty result set\n}","handlingStrategy":"type-guard","validationCode":"// check for results before iterating\nif (!iterator.hasNext()) {\n  LOG.info(\"No blobs under prefix\");\n  return Collections.emptyList();\n}","typeGuard":"boolean hasCurrent(Iterator<CloudBlobHolder> it) {\n  return it != null && it.hasNext();\n}","tryCatchPattern":"try {\n  CloudBlobHolder holder = iterator.next();\n} catch (NoSuchElementException e) {\n  LOG.warn(\"Iteration advanced past end; check hasNext() usage\", e);\n}","preventionTips":["Always iterate with while (it.hasNext()) { it.next(); }","Log prefix/container listing counts to detect unexpectedly empty listings","Never share a single iterator across threads","Handle empty-prefix cases explicitly in ingestion code"],"tags":["azure","iterator","nosuchelement"],"backgroundTag":"empty-result-set","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}