{"record":{"id":"09b432952e03ee7e","repo":"alibaba/spring-ai-alibaba","slug":"no-more-elements-into-iterator","errorCode":null,"errorMessage":"no more elements into iterator","messagePattern":"no more elements into iterator","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/async/AsyncGenerator.java","lineNumber":476,"sourceCode":"\tfinal AtomicReference<AsyncGenerator.Data<E>> currentFetchedData;\n\n\tpublic InternalIterator(AsyncGenerator<E> delegate) {\n\t\tthis.delegate = delegate;\n\t\tcurrentFetchedData = new AtomicReference<>(delegate.next());\n\t}\n\n\t@Override\n\tpublic boolean hasNext() {\n\t\tfinal var value = currentFetchedData.get();\n\t\treturn value != null && !value.isDone();\n\t}\n\n\t@Override\n\tpublic E next() {\n\t\tvar next = currentFetchedData.get();\n\n\t\tif (next == null || next.isDone()) {\n\t\t\tthrow new IllegalStateException(\"no more elements into iterator\");\n\t\t}\n\n\t\tif (!next.isError()) {\n\t\t\tcurrentFetchedData.set(delegate.next());\n\t\t}\n\n\t\treturn next.data.join();\n\t}\n\n\t@Override\n\tpublic Optional<Object> resultValue() {\n\t\tif (delegate instanceof AsyncGenerator.HasResultValue withResult) {\n\t\t\treturn withResult.resultValue();\n\t\t}\n\t\treturn Optional.empty();\n\t}\n\n};","sourceCodeStart":458,"sourceCodeEnd":494,"githubUrl":"https://github.com/alibaba/spring-ai-alibaba/blob/f82da0b50f35744c13968191be2b1cd2452ef550/spring-ai-alibaba-graph-core/src/main/java/com/alibaba/cloud/ai/graph/async/AsyncGenerator.java#L458-L494","documentation":"This iterator wraps fetched Data<E> in an AtomicReference (currentFetchedData). next() throws IllegalStateException when the previously fetched element is null or done, meaning the caller iterated past the end of the underlying delegate iterator.","triggerScenarios":"Calling next() more times than hasNext() returned true, or continuing iteration after isDone(); typically a missing hasNext() check in the consumer loop.","commonSituations":"Manual while-loops over AsyncGenerator iterators without hasNext(); code that stores the iterator and resumes pulling after completion; off-by-one loops around streamed LLM results.","solutions":["Always guard with hasNext() before calling next()","Stop iterating as soon as Data.isDone() is true","Use for-each or stream APIs over the AsyncGenerator instead of manual next() calls","If resuming iteration across async boundaries, re-check completion state before next()"],"exampleFix":"// before\nwhile (true) { E e = iterator.next(); ... } // throws at end\n// after\nwhile (iterator.hasNext()) { E e = iterator.next(); ... }","handlingStrategy":"try-catch","validationCode":"if (currentFetchedData == null || currentFetchedData.isDone()) return; // end of iteration","typeGuard":"static <E> boolean hasRemaining(java.util.Iterator<E> it) { return it.hasNext(); }","tryCatchPattern":"try { E e = it.next(); } catch (IllegalStateException e) { if (\"no more elements into iterator\".equals(e.getMessage())) { /* treat as end of stream */ } else throw e; }","preventionTips":["Always call hasNext() before next()","Prefer for-each/streams over manual iterator loops","Treat isDone() as terminal — do not resume iteration afterwards"],"tags":["async","iterator","streaming"],"backgroundTag":"internal-invariant-violation","analyzedSha":"f82da0b50f35744c13968191be2b1cd2452ef550","analyzedAt":"2026-09-09T15:32:42.421Z","contentChangedAt":"2026-09-09T15:32:42.421Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}