apache/beam · error
batch.groupIntoBatchesBufferedFn: unexpected timer family
Error message
batch.groupIntoBatchesBufferedFn: unexpected timer family %q
What it means
This panic fires in OnTimer when the delivered timer's Family matches neither fn.Buffering.Family nor fn.WindowEnd.Family. The DoFn only knows how to handle its own two timer families; an unknown family means a misconfigured or foreign timer is firing for this step, and the library treats it as an unrecoverable internal bug.
Solutions
- Check whether the pipeline was updated between versions with changed timer family names; do a clean restart (drain, cancel all state, fresh job) instead of in-place update.
- Verify no other DoFn/transform shares the same step and timer namespace.
- Report to the runner if stale timers from a cancelled job are still firing.
- Upgrade Beam to get family-name stability fixes for job updates.
- As a diagnostic, log timer.Family before the switch to identify its origin.
Example fix
// before: family names changed across a job update
fn.Buffering = tm.ProcessTime("buf_v2")
// after: keep family names stable across deployments, or fully restart the job
fn.Buffering = tm.ProcessTime("buffering") // same family name as previous version Defensive patterns
Strategy: validation
Validate before calling
// Before switching job code in-place, diff timer family names between old and // new versions; if changed, plan a full drain + fresh job restart instead.
Prevention
- Never rename timer family strings across job updates on the same state.
- Drain and fully restart jobs (discarding old timers) after timer changes.
- Avoid reusing step/state namespaces across unrelated transforms.
- Log timer.Family on unexpected values to speed diagnosis.
When it happens
Trigger: A timer callback delivers a family string that does not equal the Buffering or WindowEnd family — e.g. the pipeline was updated and an old version of the same step left timers with changed family names firing against new code, or a runner reuses/delivers timer IDs incorrectly.
Common situations: Job update (drain + restart with modified code) where the timer family string changed between versions; state/timer resurrection after job migration; runner bugs delivering stale timers from a previous job to a recycled worker.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- AfterProcessingTime trigger set without a delay or…
- At least one subtrigger required for composite triggers.
- attempted to add namespace to missing coder id
- attempted to add namespace to missing windowing strategy id
- batch: failed to marshal worker UUID
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/27cc4f0127a5cd67.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/go/pkg/beam/transforms/batch/batch.go:427
fn.flush(sp, tp, key, emit)
return
}
if fn.BatchSizeBytes > 0 && newBytes >= fn.BatchSizeBytes {
fn.flush(sp, tp, key, emit)
return
}
}
func (fn *groupIntoBatchesBufferedFn) OnTimer(
ctx context.Context, ts beam.EventTime, sp state.Provider, tp timers.Provider,
key typex.T, timer timers.Context, emit func(typex.T, []typex.V),
) {
fn.codec.init(fn.ValueType.T)
switch timer.Family {
case fn.Buffering.Family, fn.WindowEnd.Family:
fn.flush(sp, tp, key, emit)
default:
panic(fmt.Sprintf(
"batch.groupIntoBatchesBufferedFn: unexpected timer family %q", timer.Family))
}
}
func (fn *groupIntoBatchesBufferedFn) flush(
sp state.Provider, tp timers.Provider, key typex.T, emit func(typex.T, []typex.V),
) {
buf, ok, err := fn.Buffer.Read(sp)
if err != nil {
panic(err)
}
if !ok || len(buf) == 0 {
return
}
out := make([]typex.V, len(buf))
for i, b := range buf {
out[i] = fn.codec.decode(b)View on GitHub (pinned to 12126d8942)