apache/beam · error
ProcessElement uses a TimerProvider, but no Timer fields are
Error message
ProcessElement uses a TimerProvider, but no Timer fields are defined in the DoFn
What it means
A DoFn implementing TimerProvider (it uses timers in ProcessElement) must declare at least one Timer field so the framework knows which timer families to set/clear. AsDoFn validation (fn.go) fails when the keyed DoFn uses a TimerProvider but exports no Timer fields. (The USE AT entries in Python notebooks are unrelated false positives.)
Source
Thrown at sdks/go/pkg/beam/core/graph/fn.go:1429
}
} else {
return fmt.Errorf("OnTimer and ProcessElement functions for DoFn should have exactly same emitters, emitters used in OnTimer: %v, emitters used in ProcessElement: %v", otExists, peExists)
}
return nil
}
func validateTimer(fn *DoFn, numIn mainInputs) error {
pt, fieldNames := fn.PipelineTimers()
if _, ok := fn.methods[processElementName].TimerProvider(); ok {
if numIn == MainSingle {
err := errors.Errorf("ProcessElement uses a TimerProvider, but is not keyed")
return errors.SetTopLevelMsgf(err, "ProcessElement uses a TimerProvider, but is not keyed. "+
"All stateful DoFns must take a key/value pair as an input.")
}
if len(pt) == 0 {
err := errors.New("ProcessElement uses a TimerProvider, but no Timer fields are defined in the DoFn")
return errors.SetTopLevelMsgf(err, "ProcessElement uses a TimerProvider, but no timer fields are defined in the DoFn"+
", Ensure that your DoFn exports the Timer fields used to set and clear timers.")
}
timerKeys := make(map[string]string)
for i, t := range pt {
for timerFamilyID := range t.Timers() {
if timer, ok := timerKeys[timerFamilyID]; ok {
err := errors.Errorf("Duplicate timer key %v", timerFamilyID)
return errors.SetTopLevelMsgf(err, "Duplicate timer family ID %v used by struct fields %v and %v. Ensure that timer family IDs are unique per DoFn", timerFamilyID, timer, fieldNames[i])
}
timerKeys[timerFamilyID] = fieldNames[i]
}
}
if err := validateOnTimerFn(fn); err != nil {
return err
}
} else {
if len(pt) > 0 {View on GitHub (pinned to 12126d8942)
Solutions
- Add exported Timer fields to the DoFn struct, e.g. `myTimer timerprovider.Timer` created with timerprovider.NewTimer(dofn, "family").
- Ensure the timer family IDs used in ProcessElement (t.Timers()) match the declared fields.
- Confirm the DoFn input is keyed (KV) — a TimerProvider also requires a keyed input or a different error appears.
- Review the Beam timers docs and examples (sdks/go/pkg/beam/state/timerstore) for correct field wiring.
Example fix
// before
type fn struct{}
func (fn *f) ProcessElement(k string, v int, tp timerprovider.Provider) { tp.Set(...) }
// after
type fn struct {
MyTimer timerprovider.Timer
}
func (fn *f) ProcessElement(k string, v int, tp timerprovider.Provider) { fn.MyTimer.Set(...) } Defensive patterns
Strategy: validation
Validate before calling
// Before using a TimerProvider DoFn, check for exported timer fields
for _, f := range reflect.TypeOf(fn).Fields() {
if _, ok := f.Type.MethodByName("Timers"); ok { return nil }
}
return errors.New("DoFn uses TimerProvider but declares no Timer fields") Type guard
func hasTimerFields(fn interface{}) bool {
t := reflect.TypeOf(fn)
for i := 0; i < t.NumField(); i++ {
if t.Field(i).Type.Kind() == reflect.Struct && strings.Contains(t.Field(i).Type.String(), "timerprovider.Timer") {
return true
}
}
return false
} Prevention
- Create Timer fields with timerprovider.NewTimer(dofn, "family") and keep them exported.
- Match timer family IDs used in ProcessElement with declared fields.
- Ensure stateful DoFns take KV inputs when using TimerProvider.
When it happens
Trigger: Declaring a stateful, keyed DoFn whose ProcessElement takes a TimerProvider (or calls timers) without defining embedded Timer fields like `Timer timerprovider.Timer` via timerprovider.NewTimer(...), or forgetting to embed/export the timer field on the struct.
Common situations: Building stateful Beam pipelines with timers for windowed retries or session management; refactoring that removed or unexported timer fields while ProcessElement still requested a TimerProvider.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Cannot access timer in non-window observing context.
- Cannot access timerFamily in non-window observing context.
- first main input parameter must be a value type
- OnTimer function is defined for the DoFn but no TimerProvide
- OnTimer and ProcessElement functions for DoFn should have ex
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/4261e8b04bf43bf4.
Report an issue: GitHub.