Skip to content

Confusion about error.execution #644

Closed

Description

@Dolecor

The error.execution is causing me some confusion.

  1. Is it true that when defining the error_execution event in my machine, I must manually give it an id manually usingEvent(..., id="error.execution")?

    Before sending an event to the state machine, I check whether the event can be triggered using sm.allowed_events. Then I needed to catch all unhandled exceptions that could be raised by the listeners (StateChart itself, Model, etc.). I learned from the Error Handling page that this can be done by adding handlers for the error.execution event. But it seems sm.allowed_events and sm.enabled_events() conflicts with the error_execution event.

    I will demonstrate this using the ErrorLogger example from the Error Handling section:

    from statemachine import State, StateChart
    
    class ErrorLogger(StateChart):
        running = State(initial=True)
        failed = State(final=True)
    
        process = running.to(running, on="do_process")
        error_execution = running.to(failed, on="log_error")
    
        def do_process(self):
            raise ValueError("bad data")
    
        def log_error(self, error):
            self.last_error = error
    

    When I try to get enabled events after the machine reaches a stable configuration:

    sm = ErrorLogger()
    
    print(f"  Enabled events: {sm.enabled_events()}")
    

    I get the AttributeError exception:

    (.venv) PS <...>> sm-test.exe
    Traceback (most recent call last):
    File "<frozen runpy>", line 203, in _run_module_as_main
    File "<frozen runpy>", line 88, in _run_code
    File "<...>\.venv\Scripts\sm-test.exe\__main__.py", line 5, in <module>
        sys.exit(main())
                ~~~~^^
    File "<...>\src\sm_test\__main__.py", line 57, in main
        print(f"  Enabled events: {sm.enabled_events()}")
                                ~~~~~~~~~~~~~~~~~^^
    File "<...>\.venv\Lib\site-packages\statemachine\statemachine.py", line 450, in enabled_events
        result = self._engine.enabled_events(*args, **kwargs)
    File "<...>\.venv\Lib\site-packages\statemachine\engines\sync.py", line 191, in enabled_events
        "event": getattr(sm, event),
                ~~~~~~~^^^^^^^^^^^
    AttributeError: 'ErrorLogger' object has no attribute 'error.execution'. Did you mean: 'error_execution'?
    

    I found that the problem disappears if I manually assign the name error.execution to the error_execution event:

    class ErrorLogger(StateChart):
        [...]
        error_execution = Event(running.to(failed, on="log_error"), id="error.execution")
    
  2. Is it true that error_execution event, by design, can be sent to the machine from "outside"?

    When I applied the workaround with Event(..., id="error.execution"), the sm.enabled_events() gives:

    Enabled events: [BoundEvent('process', delay=0, internal=False), BoundEvent('error.execution', delay=0, internal=False)]
    

    Note that error.execution is enabled event, and it can be sent to the machine from main().

    This snippet:

    sm = ErrorLogger()
    
    print(f"  Enabled events: {sm.enabled_events()}")
    
    if "error.execution" in sm.enabled_events():
        sm.send("error.execution", error=RuntimeError("Should this be possible?"))
    
    print(sm.last_error)
    

    gives:

      Enabled events: [BoundEvent('process', delay=0, internal=False), BoundEvent('error.execution', delay=0, internal=False)]
    Should this be possible?
    

    The error.execution event is described as an internal mechanism of the machine, and it’s strange that this event can be sent from "outside".

python-statemachine versions 3.0.0, 3.1.0, 3.2.0, and 3.2.1 work identically with the specified code snippets.

Activity

  1. fgmacedo commented on Sep 13, 2026

    @fgmacedo
    Owner

    Hi @Dolecor, thanks for the detailed report, the two questions have different answers.

    1. The AttributeError is a bug, and the id= workaround is not the intended API.

    Confirmed and tracked in #654. The error_ prefix convention is supposed to register two event
    names, but _expand_event_id expresses that by returning a single space-separated string:

    class R(StateChart):
        ...
        error_execution = running.to(failed)
    
    [e.id for e in R.events]   # ['error_execution error.execution']  -- one event, glued id

    The transitions themselves receive the two correct names, which is why send("error.execution")
    works. What is wrong is the registration: add_event binds the class attribute under the glued
    id, so getattr(sm, "error.execution") in enabled_events finds nothing.

    It is not specific to the Event class or to error.execution. The plain assignment form is
    affected too, and the same applies to the done_state_ and done_invoke_ prefixes:

    class Bare(StateChart):
        a = State(initial=True)
        b = State(final=True)
        error_foo = a.to(b)
    
    Bare.error_foo    # TransitionList -- never became an event
    sm.error_foo()    # TypeError

    So sm.error_foo() has never worked for a prefixed event, only send(). Your
    Event(..., id="error.execution") workaround is correct for now, since an explicit id skips
    the expansion entirely, but it should not be necessary and you will not need it once #654 is
    fixed.

    2. Whether error.execution should be sendable from outside is a design question.

    You are right that it reads oddly. In SCXML, error.execution is raised by the platform onto the
    internal queue, so an external send("error.execution") has no counterpart in the specification.
    The library currently does not distinguish platform events from user events, which is why it
    shows up in enabled_events() and accepts an external send.

    That one is @fgmacedo's call, so I am leaving this issue open for it. Whatever the decision, the
    error.execution documentation should say explicitly whether the event is meant to be sent by
    user code, because today nothing on the Error Handling page rules it out.

  2. added this to the 3.2.2 milestone on Oct 12, 2026
  3. fgmacedo commented on Oct 12, 2026

    @fgmacedo
    Owner

    Question 2 is addressed by the docs in #671: error.execution, done.state.<id> and done.invoke.<id> are platform events raised by the engine, with no external counterpart in SCXML. The library does not enforce that today, so the new section states what happens when user code sends one anyway (no error argument reaches the handler on a bare send, and it is listed by allowed_events / enabled_events() like any other event) and shows how to filter them out when exposing events to a UI or API. No behavior change in 3.2.2.

    Question 1, the AttributeError with the error_ prefix, is fixed by the #654 work.

  4. fgmacedo commented on Oct 13, 2026

    @fgmacedo
    Owner

    Thanks again @Dolecor for the detailed report, it surfaced a real bug and a gap in the docs.

    • Question 1 (the AttributeError from enabled_events() and the need for id="error.execution"): fixed in fix: register one event per id a prefixed attribute expands to #675. The error_ prefix now registers both error_execution and error.execution as real events, so sm.error_execution(), send("error.execution"), allowed_events and enabled_events() all work without the explicit id.
    • Question 2 (sending error.execution from outside): documented in docs: state that platform events are not meant to be sent by user code #671. Platform events (error.*, done.state.*, done.invoke.*) are generated by the engine and are not meant to be sent by user code; the library does not block it today, and the Error Handling page now says so.

    Both changes ship in the upcoming 3.2.2 release (milestone: https://github.com/fgmacedo/python-statemachine/milestone/11).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions