nautechsystems/nautilus_trader · error

Python on_start failed: {e}

Error message

Python on_start failed: {e}

What it means

PyDataActorInner::on_start forwards to the actor's Python on_start override via dispatch_on_start; any Python exception in that handler is wrapped as this anyhow error. It means the actor failed during its start lifecycle, typically preventing the actor/trading node from starting correctly.

Source

Thrown at crates/common/src/python/actor.rs:1020

pub fn register_python_exec_algorithm_endpoint(exec_algorithm_id: ExecAlgorithmId) {
    let actor_id = exec_algorithm_id.inner();
    let endpoint: Ustr = format!("{exec_algorithm_id}.execute").into();
    let handler = ShareableMessageHandler::from_typed(move |command: &TradingCommand| {
        if let Some(mut algo) = try_get_actor_unchecked::<PyDataActorInner>(&actor_id) {
            if let Err(e) = algo.execute_exec_algorithm_command(command) {
                log::error!("Error executing command on Python algorithm {actor_id}: {e}");
            }
        } else {
            log::error!("Python execution algorithm {actor_id} not found in registry");
        }
    });
    msgbus::register_any(endpoint.into(), handler);
}

impl DataActor for PyDataActorInner {
    fn on_start(&mut self) -> anyhow::Result<()> {
        self.dispatch_on_start()
            .map_err(|e| anyhow::anyhow!("Python on_start failed: {e}"))
    }

    fn on_stop(&mut self) -> anyhow::Result<()> {
        self.dispatch_on_stop()
            .map_err(|e| anyhow::anyhow!("Python on_stop failed: {e}"))
    }

    fn on_resume(&mut self) -> anyhow::Result<()> {
        self.dispatch_on_resume()
            .map_err(|e| anyhow::anyhow!("Python on_resume failed: {e}"))
    }

    fn on_reset(&mut self) -> anyhow::Result<()> {
        self.dispatch_on_reset()
            .map_err(|e| anyhow::anyhow!("Python on_reset failed: {e}"))
    }

    fn on_dispose(&mut self) -> anyhow::Result<()> {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the wrapped '{e}' cause to identify the original Python exception in on_start
  2. Validate config/instrument IDs and required clients at the top of on_start and fail fast with clear messages
  3. Move long-running or error-prone work out of on_start into timers/handlers where failures are recoverable
  4. Cover actor startup in a backtest/integration test so on_start bugs surface before live deployment

Example fix

# before
def on_start(self):
    self.subscribe_quote_ticks(InstrumentId.from_str(self.config.instrument))  # None/invalid raises
# after
def on_start(self):
    if not self.config.instrument:
        self.log.error("instrument not configured")
        self.stop()
        return
    self.subscribe_quote_ticks(InstrumentId.from_str(self.config.instrument))
Defensive patterns

Strategy: try-catch

Validate before calling

def validate_config(config) -> list[str]:
    errors = []
    if not getattr(config, "instrument", None):
        errors.append("instrument is required")
    if not getattr(config, "client_id", None):
        errors.append("client_id is required")
    return errors

# call at the top of on_start; stop the actor if non-empty

Type guard

def config_ok(self) -> bool:
    return bool(getattr(self.config, "instrument", None)) and bool(
        getattr(self.config, "client_id", None)
    )

Try / catch

def on_start(self):
    try:
        self._do_start()
    except Exception as e:
        self.log.exception(f"startup failed: {e}")
        self.stop()
        raise  # re-raise only if the node must refuse to start

Prevention

When it happens

Trigger: An actor (often an exec algorithm or custom DataActor) is started and its Python on_start implementation raises — e.g. subscribing to a bad topic, requesting data with wrong parameters, or touching uninitialized state.

Common situations: Configuration mistakes surfaced at startup (missing instrument IDs, wrong client IDs), subscribing before the cache is populated, network/API calls in on_start failing, or code assuming config keys that were not provided.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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