apache/beam · error · ValueError
@on_timer decorator expected callable.
Error message
@on_timer decorator expected callable.
What it means
The function returned by @on_timer validates that the method being decorated is callable before attaching it to the TimerSpec. If the object under the decorator is not callable (e.g. a property, a constant, or a value), the decorator raises ValueError instead of silently installing a broken callback.
Solutions
- Decorate a real method: keep @on_timer(TIMER_SPEC) directly above a def with self as first parameter
- Check decorator ordering — @on_timer should wrap the actual function (place non-callable-returning decorators appropriately)
- Remove stray decorators that turn the method into a non-callable
Example fix
// before @on_timer(TIMER_SPEC) @staticmethod def expiry(self): ... // after @on_timer(TIMER_SPEC) def expiry(self): ...
Defensive patterns
Strategy: validation
Validate before calling
assert callable(method_to_decorate), '@on_timer must decorate a callable method'
Type guard
def is_callable_method(m) -> bool:
return callable(m) Try / catch
try:
_ = MyDoFn()
except ValueError as e:
if 'expected callable' in str(e):
log.error('check decorator ordering on timer callback') Prevention
- Place @on_timer(SPEC) directly above a def statement
- Avoid stacking decorators that produce non-callables (staticmethod/property ordering)
- Keep timer callbacks as plain instance methods taking self
When it happens
Trigger: Applying @on_timer(TIMER_SPEC) on top of a non-callable expression, e.g. stacking decorators that replace the method with a value, or accidentally decorating a class attribute instead of a method.
Common situations: Decorator-order mistakes (e.g. combining @staticmethod/@property with @on_timer in the wrong order); partially edited code where the def line was removed but the decorator remained.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Multiple on_timer callbacks registered for %r.
- @on_timer decorator expected TimerSpec.
- DoFn %r has a TimerSpec without an associated on_timer…
- DoFn %r has multiple TimerSpecs with the same name
- Expected a callable object instead of: %r
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/42665b720aa7ae74.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/transforms/userstate.py:237
"""Decorator for timer firing DoFn method.
This decorator allows a user to specify an on_timer processing method
in a stateful DoFn. Sample usage::
class MyDoFn(DoFn):
TIMER_SPEC = TimerSpec('timer', TimeDomain.WATERMARK)
@on_timer(TIMER_SPEC)
def my_timer_expiry_callback(self):
logging.info('Timer expired!')
"""
if not isinstance(timer_spec, TimerSpec):
raise ValueError('@on_timer decorator expected TimerSpec.')
def _inner(method: CallableT) -> CallableT:
if not callable(method):
raise ValueError('@on_timer decorator expected callable.')
if timer_spec._attached_callback:
raise ValueError(
'Multiple on_timer callbacks registered for %r.' % timer_spec)
timer_spec._attached_callback = method
return method
return _inner
def get_dofn_specs(dofn: 'DoFn') -> tuple[set[StateSpec], set[TimerSpec]]:
"""Gets the state and timer specs for a DoFn, if any.
Args:
dofn (apache_beam.transforms.core.DoFn): The DoFn instance to introspect for
timer and state specs.
"""
# Avoid circular import.View on GitHub (pinned to 12126d8942)