temporalio/temporal · error
Simple cache iterator Next called when there is no next item
Error message
Simple cache iterator Next called when there is no next item
What it means
The simple cache (common/cache/simple.go) iterator panics when Next() is called with no remaining item — the same contract as the LRU iterator. HasNext() must return true before Next() is legal. There is no graceful end-of-iteration return; the framework treats over-iteration as a caller bug.
Source
Thrown at common/cache/simple.go:46
key any
value any
}
)
// Close closes the iterator
func (it *simpleItr) Close() {
it.simple.RUnlock()
}
// HasNext return true if there is more items to be returned
func (it *simpleItr) HasNext() bool {
return it.nextItem != nil
}
// Next returns the next item
func (it *simpleItr) Next() Entry {
if it.nextItem == nil {
panic("Simple cache iterator Next called when there is no next item")
}
// nolint:revive
entry := it.nextItem.Value.(*simpleEntry)
it.nextItem = it.nextItem.Next()
// make a copy of the entry so there will be no concurrent access to this entry
entry = &simpleEntry{
key: entry.key,
value: entry.value,
}
return entry
}
func (e *simpleEntry) Key() any {
return e.key
}
func (e *simpleEntry) Value() any {View on GitHub (pinned to bde624efd1)
Solutions
- Check it.HasNext() before every Next() call
- Iterate with `for it.HasNext() { e := it.Next() ... }`
- Create a new iterator for each traversal instead of reusing exhausted ones
Example fix
// before
for i := 0; i < expectedCount; i++ {
e := it.Next() // panics if cache has fewer items
}
// after
for it.HasNext() {
e := it.Next()
process(e)
}
Defensive patterns
Strategy: validation
Validate before calling
for it.HasNext() {
e := it.Next()
process(e)
} Type guard
func nextOrNone(it *simpleItr) (cache.Entry, bool) {
if !it.HasNext() {
return nil, false
}
return it.Next(), true
} Prevention
- Guard Next() with HasNext() unconditionally
- Don't assume entry counts; iterate until HasNext is false
- Create a fresh iterator per traversal
When it happens
Trigger: Calling Next() on a simpleItr after HasNext() returned false, or calling Next() before checking at all on an empty cache snapshot; calling Next() more times than the number of entries.
Common situations: Dumping/migrating all entries from a simple cache (e.g. namespace or shard caches) with a manual counter that overruns; iterating a cache that changed size between counting and iterating; copying LRU-style loop code into simple-cache code with an off-by-one.
Related errors
- LRU cache iterator Next called when there is no next item
- Cannot use Put API in Pin mode. Use Delete and PutIfNotExist
- HistoryEventIterator Next() called without checking HasNext(
- HistoryEventIterator Next() should return either a history e
- Iterator encountered Next call when there is no next item
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/4b7bd4d713caf1c0.
Report an issue: GitHub.