apache/beam · error · ValueError

DoFn.TimerParam expected TimerSpec object.

Error message

DoFn.TimerParam expected TimerSpec object.

What it means

ValueError raised by `_TimerDoFnParam.__init__` (exposed as `DoFn.TimerParam`) when the `timer_spec` argument is not an instance of `TimerSpec`. Timers must be declared via `TimerSpec` (or `ClearableTimerSpec`) objects.

Solutions

  1. Pass a `TimerSpec` instance, e.g. `DoFn.TimerParam(TimerSpec('expiry', TimeDomain.WATERMARK))`.
  2. Confirm the argument isn't a plain string — the spec holds the name.
  3. Use `on_timer` callback decorated with `@arrow`-compatible signature matching the spec.

Example fix

// before
EXPIRY_TIMER = DoFn.TimerParam('expiry')
// after
EXPIRY_TIMER = DoFn.TimerParam(TimerSpec('expiry', TimeDomain.WATERMARK))
Defensive patterns

Strategy: type-guard

Validate before calling

from apache_beam.transforms.userstate import TimerSpec
if not isinstance(timer_spec, TimerSpec):
    raise TypeError('expected TimerSpec instance, got %r' % (timer_spec,))

Type guard

from apache_beam.transforms.userstate import TimerSpec
def is_timer_spec(x) -> bool:
    return isinstance(x, TimerSpec)

Try / catch

try:
    param = DoFn.TimerParam(spec)
except ValueError as e:
    if 'TimerSpec' in str(e):
        spec = TimerSpec(spec, TimeDomain.WATERMARK) if isinstance(spec, str) else None

Prevention

When it happens

Trigger: Writing `DoFn.TimerParam('my_timer')` or passing a state spec / string name instead of a `TimerSpec` instance when declaring a timer parameter in a DoFn.

Common situations: Passing the timer name string; mixing up StateParam and TimerParam arguments; hand-rolled timer declarations copied incorrectly from examples.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at sdks/python/apache_beam/transforms/core.py:486

        'RestrictionParam(%s)' % restriction_provider.__class__.__name__)


class _StateDoFnParam(_DoFnParam):
  """State DoFn parameter."""
  def __init__(self, state_spec):
    # type: (StateSpec) -> None
    if not isinstance(state_spec, StateSpec):
      raise ValueError("DoFn.StateParam expected StateSpec object.")
    self.state_spec = state_spec
    self.param_id = 'StateParam(%s)' % state_spec.name


class _TimerDoFnParam(_DoFnParam):
  """Timer DoFn parameter."""
  def __init__(self, timer_spec):
    # type: (TimerSpec) -> None
    if not isinstance(timer_spec, TimerSpec):
      raise ValueError("DoFn.TimerParam expected TimerSpec object.")
    self.timer_spec = timer_spec
    self.param_id = 'TimerParam(%s)' % timer_spec.name


class _BundleFinalizerParam(_DoFnParam):
  """Bundle Finalization DoFn parameter."""
  def __init__(self):
    self._callbacks = []
    self.param_id = "FinalizeBundle"

  def register(self, callback):
    self._callbacks.append(callback)

  # Log errors when calling callback to make sure all callbacks get called
  # though there are errors. And errors should not fail pipeline.
  def finalize_bundle(self):
    for callback in self._callbacks:
      try:

View on GitHub (pinned to 12126d8942)