nautechsystems/nautilus_trader · error

Python on_socket_state failed: {e}

Error message

Python on_socket_state failed: {e}

What it means

Raised by the Rust `ExecutionAlgorithm` wrapper when the Python callback `on_socket_state` throws. `SocketStateChanged` events (connection state transitions) are dispatched to the Python subclass via `dispatch_on_socket_state`; any `PyErr` raised in the user's handler is wrapped as `anyhow!("Python on_socket_state failed: {e}")`.

Source

Thrown at crates/trading/src/python/algorithm.rs:601

    fn on_time_event(&mut self, event: &TimeEvent) -> anyhow::Result<()> {
        ExecutionAlgorithm::on_time_event(self, event)?;
        self.dispatch_time_event(event)
            .map_err(|e| anyhow::anyhow!("Python on_time_event failed: {e}"))
    }

    fn on_signal(&mut self, signal: &Signal) -> anyhow::Result<()> {
        self.dispatch_on_signal(signal)
            .map_err(|e| anyhow::anyhow!("Python on_signal failed: {e}"))
    }

    fn on_queue_state(&mut self, event: &QueueStateChanged) -> anyhow::Result<()> {
        self.dispatch_on_queue_state(event)
            .map_err(|e| anyhow::anyhow!("Python on_queue_state failed: {e}"))
    }

    fn on_socket_state(&mut self, event: &SocketStateChanged) -> anyhow::Result<()> {
        self.dispatch_on_socket_state(event)
            .map_err(|e| anyhow::anyhow!("Python on_socket_state failed: {e}"))
    }
}

#[pyo3::pymethods]
#[pyo3_stub_gen::derive::gen_stub_pymethods]
#[allow(
    clippy::large_types_passed_by_value,
    reason = "PyO3 callbacks accept Python-owned event values"
)]
#[expect(
    clippy::unused_self,
    reason = "default PyO3 callbacks must remain instance methods"
)]
impl PyExecutionAlgorithm {
    /// Creates a new [`PyExecutionAlgorithm`] instance.
    #[new]
    #[pyo3(signature = (config=None))]
    fn py_new(config: Option<Py<PyAny>>) -> Self {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the chained Python traceback in the message to locate the failure inside your `on_socket_state` override
  2. Make the handler state-safe: do not assume clients/orders are usable during DISCONNECTED transitions
  3. Wrap the body in try/except and log failures instead of propagating
  4. Match the signature `def on_socket_state(self, event) -> None:` and read only documented `SocketStateChanged` fields
  5. Remove the override if you don't need socket-state visibility

Example fix

# before
def on_socket_state(self, event):
    self.client.resubscribe_all()  # raises while socket is disconnected

# after
def on_socket_state(self, event):
    try:
        if event.is_connected:
            self.client.resubscribe_all()
    except Exception as e:
        self.log.error(f"socket-state handler failed: {e}")
Defensive patterns

Strategy: try-catch

Validate before calling

sig = inspect.signature(MyAlgo.on_socket_state)
assert list(sig.parameters) == ['self', 'event']

Type guard

def is_socket_state_event(ev):
    return type(ev).__name__ == 'SocketStateChanged'

Try / catch

try:
    algo.on_socket_state(event)
except Exception as e:
    log.error(f"on_socket_state handler failed: {e}")  # resubscribe/recovery errors stay non-fatal

Prevention

When it happens

Trigger: A connection's `SocketStateChanged` event (e.g. CONNECTED/DISCONNECTED) is delivered to a registered algorithm whose Python subclass overrides `on_socket_state` and raises — e.g. reconnection logic that touches dead resources, or referencing wrong event fields.

Common situations: Custom reconnection/bookkeeping hooks that call clients or cancel orders while the socket is down; handlers written against an older event API; exceptions thrown while the adapter is shutting down.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/5ad4fe3ed579cc7f. Report an issue: GitHub.