AtsushiSakai/PythonRobotics · error · ValueError
|{self._name}| invalid transition: <{src_state.name}> : [{ev
Error message
|{self._name}| invalid transition: <{src_state.name}> : [{event}] What it means
Raised by StateMachine.state_transition when the (current state name, event) pair is not present in the transition table. The machine only accepts events explicitly declared for the current state; anything else is invalid by design.
Source
Thrown at MissionPlanning/StateMachine/state_machine.py:161
return state if isinstance(state, State) else self._get_state(state)
def get_callable(func):
return func if callable(func) else getattr(self._model, func, None)
src_state_obj = get_state_obj(src_state)
dst_state_obj = get_state_obj(dst_state)
guard_func = get_callable(guard) if guard else None
action_func = get_callable(action) if action else None
self._transition_table[(src_state_obj.name, event)] = (
dst_state_obj,
guard_func,
action_func,
)
def state_transition(self, src_state: State, event: str):
if (src_state.name, event) not in self._transition_table:
raise ValueError(
f"|{self._name}| invalid transition: <{src_state.name}> : [{event}]"
)
dst_state, guard, action = self._transition_table[(src_state.name, event)]
def call_guard(guard):
if callable(guard):
return guard()
else:
return True
def call_action(action):
if callable(action):
action()
if call_guard(guard):
call_action(action)
if src_state.name != dst_state.name:View on GitHub (pinned to 1fe4fb980f)
Solutions
- Check machine.generate_plantuml() or the transition table to see which events are valid in the current state.
- Register the missing transition with add_transition (or your machine's builder) if the event should be legal.
- Debounce/queue events so they are only dispatched in states that accept them.
Example fix
# before
machine.process('charge') # not defined from current state
# after
machine.add_transition(current_state, 'charge', charging_state)
machine.process('charge') Defensive patterns
Strategy: validation
Validate before calling
valid_events = {ev for (st, ev) in machine._transition_table if st == machine._state.name}
if event not in valid_events:
raise ValueError(f'{event} not valid in state {machine._state.name}') Try / catch
try:
machine.process(event)
except ValueError as e:
if 'invalid transition' in str(e):
log.warning('ignored stale event %s in state %s', event, machine._state.name)
else:
raise Prevention
- Inspect generate_plantuml() output to know legal events per state.
- Centralize event dispatch through a queue that filters per-state valid events.
When it happens
Trigger: Calling machine.process('some_event') while in a state that has no transition registered for that event, e.g. sending 'start' while already in the started state.
Common situations: Event-driven robots where events arrive out of order (duplicates, late events), or forgetting to register all valid (state, event) pairs when defining the machine.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of AtsushiSakai/PythonRobotics@1fe4fb980f (2026-08-28).
Data as JSON: /api/errors/ab72de928871a955.
Report an issue: GitHub.