temporalio/temporal · error
HistoryEventIterator Next() called without checking HasNext(
Error message
HistoryEventIterator Next() called without checking HasNext()
What it means
PagingIteratorImpl.Next() panics if HasNext() is false at call time. The iterator contract requires callers to check HasNext() before every Next(); calling Next() after exhaustion (or before any page is loaded) is a programming error, signaled by this panic (the message text mentions HistoryEventIterator, the original use of this generic iterator).
Source
Thrown at common/collection/paging_iterator.go:71
}
// still have local cached item to return
if iter.nextPageItemIndex < len(iter.pageItems) {
return true
}
if len(iter.pageToken) != 0 {
iter.getNextPage()
return iter.HasNext()
}
return false
}
// Next return next item or err
func (iter *PagingIteratorImpl[V]) Next() (V, error) {
if !iter.HasNext() {
panic("HistoryEventIterator Next() called without checking HasNext()")
}
if iter.pageErr != nil {
err := iter.pageErr
iter.pageErr = nil
var v V
return v, err
}
// we have cached events
if iter.nextPageItemIndex < len(iter.pageItems) {
index := iter.nextPageItemIndex
iter.nextPageItemIndex++
return iter.pageItems[index], nil
}
panic("HistoryEventIterator Next() should return either a history event or a err")
}View on GitHub (pinned to bde624efd1)
Solutions
- Use the documented loop shape: for iter.HasNext() { item, err := iter.Next(); ... }
- Return on the first non-nil error from Next(); after an error HasNext() becomes false
- If integrating third-party loops, wrap Next() with a helper that recovers panics and converts them to errors
Example fix
// before
for {
item, err := iter.Next()
if err != nil { break }
process(item)
}
// after
for iter.HasNext() {
item, err := iter.Next()
if err != nil { return err }
process(item)
} Defensive patterns
Strategy: validation
Validate before calling
if !iter.HasNext() {
return // or break out of the loop; never call Next() here
} Try / catch
func safeNext[V any](iter *collection.PagingIteratorImpl[V]) (v V, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("Next() misuse: %v", r) } }()
return iter.Next()
} Prevention
- Always iterate with `for iter.HasNext() { item, err := iter.Next(); ... }`
- Return immediately on the first Next() error
- Add a shared iteration helper so callers never hand-roll the loop
When it happens
Trigger: for { item, err := it.Next(); ... } without an it.HasNext() guard; continuing to call Next() after HasNext() returned false due to a terminal page error or exhausted token.
Common situations: Pagination loops over history events / visibility records that assume Next() returns a terminal error instead of requiring HasNext(); refactors that drop the HasNext() check.
Related errors
- HistoryEventIterator Next() should return either a history e
- Iterator encountered Next call when there is no next item
- Unable to split iterator with range %v at %v
- Unable to merge iterator range %v with incoming iterator ran
- chasm.Snapshot() called on child node: %+v
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/73f1dc71857b2dea.
Report an issue: GitHub.