apache/beam · error · ValueError

DoFn %r has multiple TimerSpecs with the same name

Error message

DoFn %r has multiple TimerSpecs with the same name: %s.

What it means

Apache Beam raises this ValueError during stateful DoFn validation when two or more TimerSpecs on a DoFn share the same timer name. Timer names must be unique per DoFn so the runner can map a firing timer back to exactly one spec. validate_stateful_dofn detects the collision by comparing the spec count against the set of unique timer names.

Solutions

  1. Rename one of the duplicate TimerSpecs so timer names are unique on the DoFn.
  2. Remove the stale/duplicate TimerSpec attribute if it is unused.
  3. List current timers with get_dofn_specs(dofn) and audit the timer names.

Example fix

// before
class MyDoFn(DoFn):
  EARLY_TIMER = TimerSpec('fire', on_timer=process_early)
  LATE_TIMER = TimerSpec('fire', on_timer=process_late)  # duplicate name
// after
class MyDoFn(DoFn):
  EARLY_TIMER = TimerSpec('early_fire', on_timer=process_early)
  LATE_TIMER = TimerSpec('late_fire', on_timer=process_late)
Defensive patterns

Strategy: validation

Validate before calling

from apache_beam.transforms.userstate import get_dofn_specs
names = [t.name for t in get_dofn_specs(MyDoFn)[1]]
assert len(names) == len(set(names)), f'duplicate timer names: {names}'

Try / catch

try:
  validate_stateful_dofn(MyDoFn)
except ValueError as e:
  if 'multiple TimerSpecs with the same name' in str(e):
    fix_duplicate_timer_names(MyDoFn)
  else:
    raise

Prevention

When it happens

Trigger: A DoFn defines two TimerSpec attributes whose TimerSpec('name') strings are identical (e.g. two TimerSpec('expiry') with different on_timer callbacks), and validate_stateful_dofn is called at pipeline construction.

Common situations: Copy-pasting a timer spec and only changing the callback but not the name; renaming a callback while leaving the old spec in place; defining the same logical timer twice across refactors.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/transforms/userstate.py:306

  # A Stateful DoFn is a DoFn that uses user state or timers.
  all_state_specs, all_timer_specs = get_dofn_specs(dofn)
  return bool(all_state_specs or all_timer_specs)


def validate_stateful_dofn(dofn: 'DoFn') -> None:
  """Validates the proper specification of a stateful DoFn."""

  # Get state and timer specs.
  all_state_specs, all_timer_specs = get_dofn_specs(dofn)

  # Reject DoFns that have multiple state or timer specs with the same name.
  if len(all_state_specs) != len(set(s.name for s in all_state_specs)):
    raise ValueError(
        'DoFn %r has multiple StateSpecs with the same name: %s.' %
        (dofn, all_state_specs))
  if len(all_timer_specs) != len(set(s.name for s in all_timer_specs)):
    raise ValueError(
        'DoFn %r has multiple TimerSpecs with the same name: %s.' %
        (dofn, all_timer_specs))

  # Reject DoFns that use timer specs without corresponding timer callbacks.
  for timer_spec in all_timer_specs:
    if not timer_spec._attached_callback:
      raise ValueError((
          'DoFn %r has a TimerSpec without an associated on_timer '
          'callback: %s.') % (dofn, timer_spec))
    method_name = timer_spec._attached_callback.__name__
    if (timer_spec._attached_callback != getattr(dofn, method_name,
                                                 None).__func__):  # type: ignore[union-attr]
      raise ValueError((
          'The on_timer callback for %s is not the specified .%s method '
          'for DoFn %r (perhaps it was overwritten?).') %
                       (timer_spec, method_name, dofn))

View on GitHub (pinned to 12126d8942)