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
- Read the wrapped '{e}' cause to identify the original Python exception in on_start
- Validate config/instrument IDs and required clients at the top of on_start and fail fast with clear messages
- Move long-running or error-prone work out of on_start into timers/handlers where failures are recoverable
- 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
- Validate all config fields before touching the bus/cache in on_start
- Never perform blocking I/O or fragile external calls directly in on_start
- Add an integration test that starts every actor against a populated cache
- Fail fast with explicit error messages instead of letting deep exceptions surface as 'Python on_start failed'
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
- Python on_start failed: {e}
- Python on_start failed: {e}
- DataActor {} must be registered before calling `clock_mut()`
- DataActor {} must be registered before calling `clock()` - t
- DataActor {} must be registered before calling `clock_ref()`
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9af7918212639ccc.
Report an issue: GitHub.