temporalio/temporal · error
HistoryEventIterator Next() should return either a history e
Error message
HistoryEventIterator Next() should return either a history event or a err
What it means
PagingIteratorImpl.Next() panics if it reaches the end of the current page while HasNext() was true — i.e. internal state (nextPageItemIndex vs pageItems vs pageToken) is inconsistent and Next() can neither return an item nor an error. This is an internal invariant assertion; the message text again references HistoryEventIterator.
Source
Thrown at common/collection/paging_iterator.go:88
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")
}
func (iter *PagingIteratorImpl[V]) getNextPage() {
items, token, err := iter.paginationFn(iter.pageToken)
if err == nil {
iter.pageItems = items
iter.pageToken = token
iter.pageErr = nil
} else {
iter.pageItems = nil
iter.pageToken = nil
iter.pageErr = err
}
iter.nextPageItemIndex = 0
}
View on GitHub (pinned to bde624efd1)
Solutions
- Do not use a PagingIteratorImpl concurrently; create one iterator per goroutine
- Ensure the paginationFn returns either items, an error, or an empty token to signal end of pagination
- Upgrade/inspect the iterator version for fixed page-state handling, and recover panics around iteration if the fn is external
Example fix
// before
items, token, err := paginationFn(token)
return items, token, nil // empty items with token, nil err
// after
if len(items) == 0 && token != "" {
return nil, "", fmt.Errorf("empty page with token")
}
return items, token, err Defensive patterns
Strategy: try-catch
Try / catch
func safeNext[V any](iter *collection.PagingIteratorImpl[V]) (v V, err error) {
defer func() { if r := recover(); r != nil { err = fmt.Errorf("iterator invariant violated: %v", r) } }()
if !iter.HasNext() { err = fmt.Errorf("iterator exhausted") ; return }
return iter.Next()
} Prevention
- Never share a PagingIteratorImpl across goroutines
- Ensure paginationFn never returns empty items with a non-empty token and nil error
- Report this panic upstream — it usually indicates a library bug rather than caller error
When it happens
Trigger: Calling Next() when the page is consumed but no further page was fetched or a terminal condition was reached without HasNext() returning false — typically from concurrent use of the iterator or a paginationFn returning an empty page with a valid token and no error.
Common situations: Sharing one PagingIteratorImpl across goroutines without synchronization; a custom paginationFn that returns (nil items, non-empty token, nil err) in a way that confuses page state.
Related errors
- HistoryEventIterator Next() called without checking HasNext(
- future has already been completed
- 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
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/9a0526ad18c1224c.
Report an issue: GitHub.