Skip to content

Fix panic in runs.Replay when the consumer breaks out early - #4

Merged
itseffi merged 1 commit into
mainfrom
fix/replay-panic-on-early-break
Aug 5, 2026
Merged

Fix panic in runs.Replay when the consumer breaks out early#4
itseffi merged 1 commit into
mainfrom
fix/replay-panic-on-early-break

Conversation

@itseffi

@itseffi itseffi commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Problem

Run.Replay forwarded every non-nil error from replayRemoteEvents into yield,
including the internal errStopReplay sentinel. That sentinel is returned at
replay.go:69 precisely because yield already returned false:

if !yield(ev, nil) {
    return errStopReplay
}

Calling yield again after it has returned false violates Go's range-over-func
contract, so any consumer breaking out of the loop panicked:

for ev, err := range run.Replay(0) {
    _ = ev
    break // panic: range function continued iteration after function for loop body returned false
}

Run.Replay is exported from pkg/productize/runs, so this is on the public API
surface. The sibling path already gets this right — replayHistoricalWindow explicitly
swallows the same sentinel at replay.go:112 (case errors.Is(replayErr, errStopReplay): return false). One path handled it; the other crashed.

Fix

The guard becomes err != nil && !errors.Is(err, errStopReplay), matching the sibling.
errors was already imported — no new dependencies, no go.mod changes. A short comment
records the invariant.

Test

TestReplayStopsCleanlyWhenConsumerBreaksEarly in tail_test.go, table-driven with
t.Parallel() per repo convention. One subtest breaks on the first event of a two-event
page; the other breaks on the first event of a HasMore: true paged reader. Both assert
exactly one event was yielded and that eventCalls stayed at 1 — proving the early break
both avoids the panic and stops paging rather than fetching the next page.

Before the fix the test panics at replay.go:33, the exact yield(events.Event{}, err)
line.

Verification

make verify passes end to end — fmt, lint with 0 issues., 3668 tests, and the build.
Also verified merged together with the runs purge context fix on an integration branch:
3669 tests, gate green.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@itseffi
itseffi merged commit e07cb6a into main Aug 5, 2026
4 checks passed
@itseffi
itseffi deleted the fix/replay-panic-on-early-break branch August 5, 2026 10:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant