apache/beam · error · ValueError
Unsupported TimeDomain: %r.
Error message
Unsupported TimeDomain: %r.
What it means
TimerSpec.__init__ accepts only TimeDomain.WATERMARK or TimeDomain.REAL_TIME as the time_domain argument. Any other value (arbitrary strings, EVENT_TIME misspellings, processing-time variants) is rejected with a ValueError, since the runner needs a well-defined time domain to schedule the timer.
Solutions
- Use TimeDomain.WATERMARK for event-time timers or TimeDomain.REAL_TIME for processing-time timers
- Import TimeDomain from apache_beam.transforms.userstate and use the enum members rather than raw strings
- Fix misspellings — e.g. 'processing_time' should be TimeDomain.REAL_TIME
Example fix
// before
spec = TimerSpec('my_timer', 'processing_time')
// after
from apache_beam.transforms.userstate import TimeDomain
spec = TimerSpec('my_timer', TimeDomain.REAL_TIME) Defensive patterns
Strategy: validation
Validate before calling
from apache_beam.transforms.userstate import TimeDomain
assert time_domain in (TimeDomain.WATERMARK, TimeDomain.REAL_TIME), f'bad time_domain: {time_domain!r}' Type guard
def is_valid_time_domain(td) -> bool:
return td in (TimeDomain.WATERMARK, TimeDomain.REAL_TIME) Try / catch
try:
spec = TimerSpec('t', time_domain)
except ValueError as e:
raise ValueError(f'fix time_domain, must be TimeDomain.WATERMARK or REAL_TIME: {e}') Prevention
- Only use TimeDomain enum members, never raw strings
- Remember Beam Python names: WATERMARK (event time) and REAL_TIME (processing time)
- Construct TimerSpecs at module level so mistakes fail at import, not at pipeline run
When it happens
Trigger: TimerSpec('name', 'processing_time') with a wrong string; passing TimeDomain.EVENT_TIME or other enum members not in (WATERMARK, REAL_TIME); passing None or an int instead of a TimeDomain member.
Common situations: Typos like 'processingtime'; copy-pasting from other streaming frameworks that use different time-domain enums; assuming PROCESSING_TIME is a valid name when the Beam Python SDK calls it REAL_TIME.
Understand the failure class
Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.
Related errors
- Cannot access time domain outside of @ProcessTimer method.
- DoFn %r has a TimerSpec without an associated on_timer…
- DoFn %r has multiple TimerSpecs with the same name
- Multiple on_timer callbacks registered for %r.
- NotImplementedError
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/081aa324182e59b3.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/transforms/userstate.py:202
('clear_bit', bool),
('fire_timestamp', Optional['Timestamp']),
('hold_timestamp', Optional['Timestamp']),
('paneinfo', Optional['windowed_value.PaneInfo']),
])
# TODO(BEAM-9562): Plumb through actual key_coder and window_coder.
class TimerSpec(object):
"""Specification for a user stateful DoFn timer.
Read more about Timers here:
https://beam.apache.org/documentation/programming-guide/#timers
"""
prefix = "ts-"
def __init__(self, name: str, time_domain: str) -> None:
self.name = self.prefix + name
if time_domain not in (TimeDomain.WATERMARK, TimeDomain.REAL_TIME):
raise ValueError('Unsupported TimeDomain: %r.' % (time_domain, ))
self.time_domain = time_domain
self._attached_callback: Optional[Callable] = None
def __repr__(self) -> str:
return '%s(%s)' % (self.__class__.__name__, self.name)
def to_runner_api(
self, context: 'PipelineContext', key_coder: Coder,
window_coder: Coder) -> beam_runner_api_pb2.TimerFamilySpec:
return beam_runner_api_pb2.TimerFamilySpec(
time_domain=TimeDomain.to_runner_api(self.time_domain),
timer_family_coder_id=context.coders.get_id(
coders._TimerCoder(key_coder, window_coder)))
def on_timer(timer_spec: TimerSpec) -> Callable[[CallableT], CallableT]:
"""Decorator for timer firing DoFn method.
View on GitHub (pinned to 12126d8942)