{"record":{"id":"3587d34bb9d44801","repo":"apache/beam","slug":"ontimer-function-not-defined-for-dofn-v-ensure-that-ontimer","errorCode":null,"errorMessage":"OnTimer function not defined for DoFn: %v. Ensure that OnTimer function is implemented for the DoFn.","messagePattern":"OnTimer function not defined for DoFn: (.+?)\\. Ensure that OnTimer function is implemented for the DoFn\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/fn.go","lineNumber":1393,"sourceCode":"\t\t\t}\n\t\t\tstateKeys[k] = s\n\t\t}\n\t} else {\n\t\tif len(ps) > 0 {\n\t\t\terr := errors.Errorf(\"ProcessElement doesn't use a StateProvider, but State structs are attached to \"+\n\t\t\t\t\"the DoFn: %v\", ps)\n\t\t\treturn errors.SetTopLevelMsgf(err, \"ProcessElement doesn't use a StateProvider, but State structs are \"+\n\t\t\t\t\"attached to the DoFn: %v\\nEnsure that you are using the StateProvider to perform any reads or writes\"+\n\t\t\t\t\"of pipeline state.\", ps)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc validateOnTimerFn(fn *DoFn) error {\n\tif _, ok := fn.methods[onTimerName]; !ok {\n\t\terr := errors.Errorf(\"OnTimer function not defined for DoFn: %v\", fn.Name())\n\t\treturn errors.SetTopLevelMsgf(err, \"OnTimer function not defined for DoFn: %v. Ensure that OnTimer function is implemented for the DoFn.\", fn.Name())\n\t}\n\n\tpipelineTimers, _ := fn.PipelineTimers()\n\n\tif _, ok := fn.methods[onTimerName].TimerProvider(); !ok {\n\t\terr := errors.Errorf(\"OnTimer function doesn't use a TimerProvider, but Timer field is attached to the DoFn(%v): %v\", fn.Name(), pipelineTimers)\n\t\treturn errors.SetTopLevelMsgf(err, \"OnTimer function doesn't use a TimerProvider, but Timer field is attached to the DoFn(%v): %v\"+\n\t\t\t\", Ensure that you are using the TimerProvider to set and clear the timers.\", fn.Name(), pipelineTimers)\n\t}\n\n\t_, otNum, otExists := fn.methods[onTimerName].Emits()\n\t_, peNum, peExists := fn.methods[processElementName].Emits()\n\n\tif otExists == peExists {\n\t\tif otNum != peNum {\n\t\t\treturn fmt.Errorf(\"OnTimer and ProcessElement functions for DoFn should have exactly same emitters, no. of emitters used in OnTimer: %v, no. of emitters used in ProcessElement: %v\", otNum, peNum)\n\t\t}","sourceCodeStart":1375,"sourceCodeEnd":1411,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/fn.go#L1375-L1411","documentation":"Beam Go requires any DoFn participating in timers to implement an OnTimer method. When validation detects a DoFn set up for timers (or pipeline validation reaches the timer check) but fn.methods has no entry for onTimerName, this error is thrown: callbacks fired by timers have nowhere to be dispatched.","triggerScenarios":"Attaching Timer fields or a TimerProvider to a DoFn but not defining func (fn *X) OnTimer(ctx, ts, t) ...; implementing ProcessElement with timer logic and forgetting the OnTimer callback.","commonSituations":"Setting event-time timers in ProcessElement without defining the handler; copying only the ProcessElement half of a timer example; renames/refactors dropping the OnTimer method.","solutions":["Implement the OnTimer method on the DoFn with the correct signature (context, timer.Set/OnTimer callback args).","Match the timer IDs set via the TimerProvider with the ones handled in OnTimer.","Refer to Beam's timer example DoFn and copy the complete pair (ProcessElement + OnTimer)."],"exampleFix":"// before\ntype BatchFn struct{ T timer.Provider }\nfunc (fn *BatchFn) ProcessElement(ctx context.Context, tp timer.Provider, k beam.KV[string, string]) error {\n    tp.Set(...) // timers set, no OnTimer defined\n}\n// after\nfunc (fn *BatchFn) OnTimer(ctx context.Context, ts timer.Signals, k beam.KV[string, string]) error {\n    // handle expiry\n}","handlingStrategy":"validation","validationCode":"var _ interface {\n    OnTimer(context.Context, timer.Signals, beam.KV[string, string]) error\n} = (*BatchFn)(nil) // compile-time check that OnTimer is implemented","typeGuard":"func implementsOnTimer(fn interface{}) bool {\n    _, ok := fn.(interface{ OnTimer(context.Context, timer.Signals) error })\n    return ok\n}","tryCatchPattern":"if err := beam.Run(ctx, p); err != nil {\n    if strings.Contains(err.Error(), \"OnTimer function not defined\") {\n        log.Fatalf(\"implement OnTimer for %T: %v\", dofn, err)\n    }\n    return err\n}","preventionTips":["Always implement ProcessElement and OnTimer together when using timers","Use a compile-time interface assertion for OnTimer on timer DoFns","Copy complete DoFn examples, not fragments"],"tags":["go","apache-beam","dofn","timers","method-not-implemented"],"backgroundTag":"method-not-implemented","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}