apache/beam · error

OnTimer and ProcessElement functions for DoFn should have ex

Error message

OnTimer and ProcessElement functions for DoFn should have exactly same emitters, emitters used in OnTimer: %v, emitters used in ProcessElement: %v

What it means

Companion to the emitter-count mismatch: Beam requires that either both OnTimer and ProcessElement emit outputs or neither does. This error fires when one method has emitters and the other does not (the existence flags differ), which the framework treats as an invalid DoFn shape.

Source

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

	}

	pipelineTimers, _ := fn.PipelineTimers()

	if _, ok := fn.methods[onTimerName].TimerProvider(); !ok {
		err := errors.Errorf("OnTimer function doesn't use a TimerProvider, but Timer field is attached to the DoFn(%v): %v", fn.Name(), pipelineTimers)
		return errors.SetTopLevelMsgf(err, "OnTimer function doesn't use a TimerProvider, but Timer field is attached to the DoFn(%v): %v"+
			", Ensure that you are using the TimerProvider to set and clear the timers.", fn.Name(), pipelineTimers)
	}

	_, otNum, otExists := fn.methods[onTimerName].Emits()
	_, peNum, peExists := fn.methods[processElementName].Emits()

	if otExists == peExists {
		if otNum != peNum {
			return 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)
		}
	} 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.")

View on GitHub (pinned to 12126d8942)

Solutions

  1. Add emit parameters to OnTimer matching ProcessElement's outputs (or remove them from both).
  2. If OnTimer legitimately produces no output, remove emit parameters from ProcessElement too, or move emitting logic into another DoFn.
  3. Keep both method signatures in sync whenever you change output types.

Example fix

// before
func (f *myFn) ProcessElement(ctx context.Context, x string, emit func(string))
func (f *myFn) OnTimer(ctx context.Context, t timer.Event)
// after
func (f *myFn) ProcessElement(ctx context.Context, x string, emit func(string))
func (f *myFn) OnTimer(ctx context.Context, t timer.Event, emit func(string))
Defensive patterns

Strategy: validation

Validate before calling

// Assert at build time that both methods either both have or both lack emit params.
if hasEmits(fn.ProcessElement) != hasEmits(fn.OnTimer) { return errors.New("emitter existence mismatch") }

Type guard

func hasEmits(method interface{}) bool { t := reflect.TypeOf(method); if t.Kind() == reflect.Func { for i := 0; i < t.NumIn(); i++ { if isEmitType(t.In(i)) { return true } } }; return false }

Try / catch

if err := beam.ParDo(scope, fn, input); err != nil { return fmt.Errorf("emitter mismatch: %w", err) }

Prevention

When it happens

Trigger: Defining a DoFn whose ProcessElement has emit parameters but whose OnTimer has none (or vice versa), then validating/registering the DoFn in a pipeline.

Common situations: Adding OnTimer to an existing emitting DoFn with a bare context-only signature; removing all emit parameters from OnTimer during refactoring while ProcessElement still emits.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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