{"record":{"id":"933c15968dc2bf35","repo":"stanfordnlp/CoreNLP","slug":"called-next-without-hasnext","errorCode":null,"errorMessage":"Called next without hasNext","messagePattern":"Called next without hasNext","errorType":"exception","errorClass":"IllegalAccessError","httpStatus":null,"severity":"error","filePath":"src/edu/stanford/nlp/util/Iterables.java","lineNumber":411,"sourceCode":"      Iterator<V1> iterA = iter1.iterator();\n      Iterator<V2> iterB = iter2.iterator();\n\n      public Iterator<Pair<V1, V2>> iterator() {\n        return new Iterator<Pair<V1,V2>>() {\n          boolean ready = false;\n          Pair<V1,V2> pending = null;\n\n          public boolean hasNext() {\n            if (!ready) {\n              pending = nextPair();\n              ready = true;\n            }\n            return pending != null;\n          }\n\n          public Pair<V1, V2> next() {\n            if (!ready && !hasNext()) {\n              throw new IllegalAccessError(\"Called next without hasNext\");\n            }\n            ready = false;\n            return pending;\n          }\n\n          public void remove() {\n            throw new UnsupportedOperationException(\"Cannot remove pairs \" +\n            \"from a merged iterator\");\n          }\n\n          private Pair<V1,V2> nextPair() {\n            V1 nextA = null;\n            V2 nextB = null;\n\n            while (iterA.hasNext() && iterB.hasNext()) {\n              // increment iterators are null\n              if (nextA == null) { nextA = iterA.next(); }\n              if (nextB == null) { nextB = iterB.next(); }","sourceCodeStart":393,"sourceCodeEnd":429,"githubUrl":"https://github.com/stanfordnlp/CoreNLP/blob/1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a/src/edu/stanford/nlp/util/Iterables.java#L393-L429","documentation":"The merged Pair iterator over two value collections buffers one pending pair. next() checks the ready flag; if next() is called before hasNext() ever primed the buffer (and hasNext() confirms no more pairs), the call is an iterator-protocol violation and throws.","triggerScenarios":"Calling next() as the first operation on the merged iterator, or calling next() twice in a row without an intervening hasNext().","commonSituations":"Assuming iterators always have a first element, iterating two maps whose entry sets are empty, or sloppy manual iterator loops over merged collections.","solutions":["Call hasNext() before every next() call","Prefer for-each over the merged Iterable view","Check that both underlying maps/collections are non-empty when at least one pair is expected","Create a fresh iterator after exhaustion instead of reusing it"],"exampleFix":"// before\nPair<V1,V2> p = mergedIterator.next();\n// after\nif (mergedIterator.hasNext()) {\n  Pair<V1,V2> p = mergedIterator.next();\n}","handlingStrategy":"type-guard","validationCode":"boolean has = mergedIterator.hasNext();\nif (has) { Pair<V1,V2> p = mergedIterator.next(); }","typeGuard":"static <A,B> java.util.Optional<Pair<A,B>> nextPairIfPresent(java.util.Iterator<Pair<A,B>> it) {\n  return it.hasNext() ? java.util.Optional.of(it.next()) : java.util.Optional.empty();\n}","tryCatchPattern":"try {\n  Pair<V1,V2> p = mergedIterator.next();\n} catch (IllegalAccessError e) {\n  // called next without hasNext: recover by restarting loop with hasNext guard\n  p = null;\n}","preventionTips":["Guard every next() with hasNext()","Prefer for-each over merged Iterable views","Verify underlying maps are non-empty when a pair is expected","Never call next() twice without hasNext() in between"],"tags":["iterator","java-collections","misuse"],"backgroundTag":"iterator-next-without-hasnext","analyzedSha":"1b7edd19c4d0d7b1f13a2591425b9b60a0b1af7a","analyzedAt":"2026-09-10T02:24:07.274Z","contentChangedAt":"2026-09-10T02:24:07.274Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}