nautechsystems/nautilus_trader · error
Python on_signal failed: {e}
Error message
Python on_signal failed: {e} What it means
Raised by the Rust `ExecutionAlgorithm` wrapper when the Python callback `on_signal` throws an exception. Signals routed through the trader are passed to the Python subclass via `dispatch_on_signal`; any `PyErr` raised inside the user's handler is wrapped as `anyhow!("Python on_signal failed: {e}")`.
Source
Thrown at crates/trading/src/python/algorithm.rs:591
fn on_degrade(&mut self) -> anyhow::Result<()> {
self.dispatch_no_args("on_degrade")
.map_err(|e| anyhow::anyhow!("Python on_degrade failed: {e}"))
}
fn on_fault(&mut self) -> anyhow::Result<()> {
self.dispatch_no_args("on_fault")
.map_err(|e| anyhow::anyhow!("Python on_fault failed: {e}"))
}
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"View on GitHub (pinned to 18893faf8b)
Solutions
- Read the chained Python traceback in the message to find the real exception inside your `on_signal` override
- Validate/parse `signal.data` defensively before using it (check type, decode with fallback)
- Add try/except around signal parsing and log-and-drop invalid signals instead of raising
- Ensure the published signal's data type matches what `on_signal` unpacks
- Confirm the override signature is `def on_signal(self, signal) -> None:`
Example fix
# before
def on_signal(self, signal):
payload = json.loads(signal.data.value)["target"] # KeyError on malformed signal
# after
def on_signal(self, signal):
try:
payload = json.loads(signal.data.value).get("target")
except (ValueError, AttributeError) as e:
self.log.error(f"Bad signal {signal.topic}: {e}")
return
if payload is None:
return Defensive patterns
Strategy: validation
Validate before calling
def safe_on_signal(signal):
raw = getattr(signal, 'data', None)
return raw is not None # validate before parsing in on_signal Type guard
def is_parseable_signal(signal):
data = getattr(signal, 'data', None)
return data is not None and hasattr(data, 'value') Try / catch
try:
algo.on_signal(signal)
except Exception as e:
log.error(f"on_signal failed for topic '{getattr(signal, 'topic', '?')}': {e}") Prevention
- Validate signal payload schema at publish time, not only at consume time
- Parse `signal.data` with try/except and drop malformed signals with a log entry
- Keep publisher and consumer signal data types in sync (same `DataType`/topic)
- Add a schema/version tag to custom signals so handlers can reject unknown versions gracefully
When it happens
Trigger: Publishing/receiving a `Signal` that is dispatched to a registered execution algorithm whose Python subclass overrides `on_signal` and raises — e.g. parsing `signal.data` with the wrong type, assuming a custom data type that doesn't match, or errors in signal-driven order logic.
Common situations: Signal payloads parsed with `json.loads` failing on malformed data; custom `DataType` mismatches between the publisher and the algorithm; missing signal topic handlers; errors after strategy config changes.
Related errors
- Python on_fault failed: {e}
- Python on_time_event failed: {e}
- Python on_queue_state failed: {e}
- Python on_socket_state failed: {e}
- Python on_pool_swap failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5f254af24169549a.
Report an issue: GitHub.