apache/beam · error

OnTimer function is defined for the DoFn but no TimerProvide

Error message

OnTimer function is defined for the DoFn but no TimerProvider defined in ProcessElement

What it means

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.

Source

Thrown at sdks/go/pkg/beam/core/graph/fn.go:1453

			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 {
			err := errors.Errorf("ProcessElement doesn't use a TimerProvider, but Timer field is attached to the DoFn: %v", pt)
			return errors.SetTopLevelMsgf(err, "ProcessElement doesn't use a TimerProvider, but Timer field is attached to the DoFn: %v"+
				", Ensure that you are using the TimerProvider to set and clear the timers.", pt)
		}
		if err := validateOnTimerFn(fn); err == nil {
			actualErr := errors.New("OnTimer function is defined for the DoFn but no TimerProvider defined in ProcessElement")
			return errors.SetTopLevelMsgf(actualErr, "OnTimer function is defined for the DoFn but no TimerProvider defined in ProcessElement."+
				"Ensure that timers.Provider is defined in the ProcessElement and OnTimer methods of DoFn.")
		}
	}

	return nil
}

// CombineFn represents a CombineFn.
type CombineFn Fn

// SetupFn returns the "Setup" function, if present.
func (f *CombineFn) SetupFn() *funcx.Fn {
	return f.methods[setupName]
}

// CreateAccumulatorFn returns the "CreateAccumulator" function, if present.
func (f *CombineFn) CreateAccumulatorFn() *funcx.Fn {

View on GitHub (pinned to 12126d8942)

Solutions

  1. Add a timers.Provider parameter to the DoFn's ProcessElement method signature.
  2. Ensure the OnTimer method and any Timer fields use the provider passed to ProcessElement.
  3. Re-run pipeline construction; validation should pass once the provider is present.

Example fix

// before
func (d *myFn) ProcessElement(ctx context.Context, elm string) { ... }
func (d *myFn) OnTimer(ts string, t timers.Context) { ... }
// after
func (d *myFn) ProcessElement(ctx context.Context, tp timers.Provider, elm string) { ... }
func (d *myFn) OnTimer(ts string, t timers.Context) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// Validate the DoFn before adding it to the pipeline
if hasMethod(fn, "OnTimer") && !processElementAccepts(fn, reflect.TypeOf((*timers.Provider)(nil))) {
    return fmt.Errorf("DoFn %T defines OnTimer but ProcessElement lacks timers.Provider", fn)
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/d4d525022d586199. Report an issue: GitHub.