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

  1. Check machine.generate_plantuml() or the transition table to see which events are valid in the current state.
  2. Register the missing transition with add_transition (or your machine's builder) if the event should be legal.
  3. 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

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.