{"record":{"id":"d4d525022d586199","repo":"apache/beam","slug":"ontimer-function-is-defined-for-the-dofn-but-no","errorCode":null,"errorMessage":"OnTimer function is defined for the DoFn but no TimerProvider defined in ProcessElement","messagePattern":"OnTimer function is defined for the DoFn but no TimerProvider defined in ProcessElement","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"sdks/go/pkg/beam/core/graph/fn.go","lineNumber":1453,"sourceCode":"\t\t\tfor timerFamilyID := range t.Timers() {\n\t\t\t\tif timer, ok := timerKeys[timerFamilyID]; ok {\n\t\t\t\t\terr := errors.Errorf(\"Duplicate timer key %v\", timerFamilyID)\n\t\t\t\t\treturn 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])\n\t\t\t\t}\n\t\t\t\ttimerKeys[timerFamilyID] = fieldNames[i]\n\t\t\t}\n\t\t}\n\t\tif err := validateOnTimerFn(fn); err != nil {\n\t\t\treturn err\n\t\t}\n\t} else {\n\t\tif len(pt) > 0 {\n\t\t\terr := errors.Errorf(\"ProcessElement doesn't use a TimerProvider, but Timer field is attached to the DoFn: %v\", pt)\n\t\t\treturn errors.SetTopLevelMsgf(err, \"ProcessElement doesn't use a TimerProvider, but Timer field is attached to the DoFn: %v\"+\n\t\t\t\t\", Ensure that you are using the TimerProvider to set and clear the timers.\", pt)\n\t\t}\n\t\tif err := validateOnTimerFn(fn); err == nil {\n\t\t\tactualErr := errors.New(\"OnTimer function is defined for the DoFn but no TimerProvider defined in ProcessElement\")\n\t\t\treturn errors.SetTopLevelMsgf(actualErr, \"OnTimer function is defined for the DoFn but no TimerProvider defined in ProcessElement.\"+\n\t\t\t\t\"Ensure that timers.Provider is defined in the ProcessElement and OnTimer methods of DoFn.\")\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// CombineFn represents a CombineFn.\ntype CombineFn Fn\n\n// SetupFn returns the \"Setup\" function, if present.\nfunc (f *CombineFn) SetupFn() *funcx.Fn {\n\treturn f.methods[setupName]\n}\n\n// CreateAccumulatorFn returns the \"CreateAccumulator\" function, if present.\nfunc (f *CombineFn) CreateAccumulatorFn() *funcx.Fn {","sourceCodeStart":1435,"sourceCodeEnd":1471,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/go/pkg/beam/core/graph/fn.go#L1435-L1471","documentation":"Beam validates that a DoFn which declares an OnTimer method also receives a timers.Provider in its ProcessElement signature; timers can only be set/cleared through that provider. validateOnTimerFn succeeds (an OnTimer callback exists) but the ProcessElement signature lacks the timers.Provider parameter, so fn.go returns this top-level error during DoFn validation.","triggerScenarios":"Registering a DoFn whose ProcessElement does not declare a timers.Provider parameter while the same DoFn defines an OnTimer method (or Timer-typed fields), then building the pipeline graph so fn.go's validation runs.","commonSituations":"Adding an OnTimer method to an existing DoFn but forgetting to add the timers.Provider argument to ProcessElement; copying timer examples and dropping the provider parameter; upgrading Beam and converting old callback-style timer code to the provider API.","solutions":["Add a timers.Provider parameter to the DoFn's ProcessElement method signature.","Ensure the OnTimer method and any Timer fields use the provider passed to ProcessElement.","Re-run pipeline construction; validation should pass once the provider is present."],"exampleFix":"// before\nfunc (d *myFn) ProcessElement(ctx context.Context, elm string) { ... }\nfunc (d *myFn) OnTimer(ts string, t timers.Context) { ... }\n// after\nfunc (d *myFn) ProcessElement(ctx context.Context, tp timers.Provider, elm string) { ... }\nfunc (d *myFn) OnTimer(ts string, t timers.Context) { ... }","handlingStrategy":"validation","validationCode":"// Validate the DoFn before adding it to the pipeline\nif hasMethod(fn, \"OnTimer\") && !processElementAccepts(fn, reflect.TypeOf((*timers.Provider)(nil))) {\n    return fmt.Errorf(\"DoFn %T defines OnTimer but ProcessElement lacks timers.Provider\", fn)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Whenever adding OnTimer to a DoFn, add timers.Provider to ProcessElement in the same change","Run beam validate/unit-test pipeline construction in CI to catch DoFn signature errors early","Copy from official Beam timer examples rather than hand-writing signatures"],"tags":["go","apache-beam","dofn","timers","validation"],"backgroundTag":"missing-required-argument","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"}