{"record":{"id":"98ec0a14d07b5f2b","repo":"redis/jedis","slug":"no-more-aggregation-results-available","errorCode":null,"errorMessage":"No more aggregation results available","messagePattern":"No more aggregation results available","errorType":"exception","errorClass":"NoSuchElementException","httpStatus":null,"severity":"error","filePath":"src/main/java/redis/clients/jedis/search/aggr/AggregateIterator.java","lineNumber":110,"sourceCode":"      throw new JedisException(\"No connections available from connection provider\");\n    }\n    // Randomly select an entry from the map to distribute load across shards\n    List<? extends Map.Entry<?, ?>> entries = new ArrayList<>(connectionMap.entrySet());\n    this.connectionEntry = entries.get(ThreadLocalRandom.current().nextInt(entries.size()));\n\n    // Execute initial aggregation command\n    initializeAggregation(aggregationBuilder);\n  }\n\n  @Override\n  public boolean hasNext() {\n    return aggrCommandResult != null || cursorId != null && cursorId > 0;\n  }\n\n  @Override\n  public AggregationResult next() {\n    if (!hasNext()) {\n      throw new NoSuchElementException(\"No more aggregation results available\");\n    }\n\n    try {\n      if (aggrCommandResult != null) {\n        try {\n          return aggrCommandResult;\n        } finally {\n          aggrCommandResult = null;\n        }\n      } else {\n        return doFetch();\n      }\n\n    } catch (Exception e) {\n      throw new JedisException(\"Failed to fetch next aggregation batch\", e);\n    }\n  }\n","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/redis/jedis/blob/6dac31d4c224fb3257c216f3985340c6f500cdcb/src/main/java/redis/clients/jedis/search/aggr/AggregateIterator.java#L92-L128","documentation":"Thrown by AggregateIterator.next() when called after the aggregation cursor is exhausted: the current batch was already returned, and there is no cursorId left to fetch the next batch. It is a standard Iterator contract violation (NoSuchElementException), signalling the caller iterated past the end of the aggregation results.","triggerScenarios":"Calling next() again after hasNext() returns false — i.e. after the initial batch was consumed and cursorId is null or 0.","commonSituations":"Manual while loops without checking hasNext(); calling next() a fixed number of times assuming a batch size; reusing an exhausted AggregateIterator for a second pass.","solutions":["Guard every next() call with hasNext() and stop iterating when it returns false","Use a for-each loop or the iterator in a standard while(hasNext()) pattern instead of manual index-based loops","If you need to re-run the aggregation, build a new AggregateIterator rather than reusing the exhausted one"],"exampleFix":"// before\nAggregationResult r = iterator.next(); // NoSuchElementException after exhaustion\n// after\nwhile (iterator.hasNext()) {\n  AggregationResult r = iterator.next();\n  // process batch\n}","handlingStrategy":"type-guard","validationCode":"// call site guard\nif (!iterator.hasNext()) return; // or break the loop","typeGuard":"boolean canAdvance(java.util.Iterator<AggregationResult> it) {\n  return it != null && it.hasNext();\n}","tryCatchPattern":"try {\n  AggregationResult r = iterator.next();\n} catch (java.util.NoSuchElementException e) {\n  // iteration past end — treat as loop-exit bug, not a data error\n}","preventionTips":["Always iterate with while(iterator.hasNext()) or for-each","Never call next() a fixed number of times; batch sizes are not guaranteed","Do not reuse an exhausted AggregateIterator; create a new one for a new pass"],"tags":["jedis","search","aggregation","iterator","nosuchelement"],"backgroundTag":"empty-result-set","analyzedSha":"6dac31d4c224fb3257c216f3985340c6f500cdcb","analyzedAt":"2026-09-08T04:55:01.204Z","contentChangedAt":"2026-09-08T04:55:01.204Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}