apache/beam · error · ValueError
DoFn %r has multiple StateSpecs with the same name
Error message
DoFn %r has multiple StateSpecs with the same name: %s.
What it means
Apache Beam raises this ValueError during stateful DoFn validation when two or more StateSpecs on a DoFn share the same name. State specs are keyed by name, so duplicates would make state access ambiguous. validate_stateful_dofn detects the duplicate by comparing the spec count against the set of unique names before the pipeline runs.
Solutions
- Rename one of the duplicate StateSpecs so every state name on the DoFn is unique.
- If the duplicate is leftover dead code, delete the unused StateSpec attribute.
- Check all specs via apache_beam.transforms.userstate.get_dofn_specs(dofn) to list names before re-running.
Example fix
// before
class CountingDoFn(DoFn):
COUNTER_SPEC = ReadStateSpec('cells')
HISTORY_SPEC = ReadStateSpec('cells') # duplicate name
// after
class CountingDoFn(DoFn):
COUNTER_SPEC = ReadStateSpec('cells')
HISTORY_SPEC = ReadStateSpec('history') Defensive patterns
Strategy: validation
Validate before calling
from apache_beam.transforms.userstate import get_dofn_specs
names = [s.name for s in get_dofn_specs(MyDoFn)[0]]
assert len(names) == len(set(names)), f'duplicate state names: {names}' Try / catch
try:
validate_stateful_dofn(MyDoFn)
except ValueError as e:
if 'multiple StateSpecs with the same name' in str(e):
fix_duplicate_state_names(MyDoFn)
else:
raise Prevention
- Give each StateSpec a distinct, descriptive name string.
- After refactoring a DoFn, run validate_stateful_dofn in a unit test.
- Grep the DoFn class for repeated StateSpec('name') literals before committing.
When it happens
Trigger: A DoFn class defines two class-level StateSpec attributes with the same name string, e.g. two ReadStateSpec('my_state') entries (or the same name reused across state types). validate_stateful_dofn is invoked during pipeline construction/execution and len(all_state_specs) != len(set(names)).
Common situations: Copy-pasting a state spec and forgetting to rename it; refactoring where two specs accidentally converge to one name; merging branches of a DoFn that each declared a state with the same string name.
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
- DoFn %r has multiple TimerSpecs with the same name
- An unsupported sink was specified
- At least one of --render_port or --render_output must be…
- buffer_sec must be >= 0, got
- Cannot skip negative number of header lines
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/0fc344b9e4d14f1a.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/transforms/userstate.py:302
def is_stateful_dofn(dofn: 'DoFn') -> bool:
"""Determines whether a given DoFn is a stateful DoFn."""
# 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 'View on GitHub (pinned to 12126d8942)