{"record":{"id":"5f254af24169549a","repo":"nautechsystems/nautilus_trader","slug":"python-on-signal-failed-e-5f254a","errorCode":null,"errorMessage":"Python on_signal failed: {e}","messagePattern":"Python on_signal failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/trading/src/python/algorithm.rs","lineNumber":591,"sourceCode":"    fn on_degrade(&mut self) -> anyhow::Result<()> {\n        self.dispatch_no_args(\"on_degrade\")\n            .map_err(|e| anyhow::anyhow!(\"Python on_degrade failed: {e}\"))\n    }\n\n    fn on_fault(&mut self) -> anyhow::Result<()> {\n        self.dispatch_no_args(\"on_fault\")\n            .map_err(|e| anyhow::anyhow!(\"Python on_fault failed: {e}\"))\n    }\n\n    fn on_time_event(&mut self, event: &TimeEvent) -> anyhow::Result<()> {\n        ExecutionAlgorithm::on_time_event(self, event)?;\n        self.dispatch_time_event(event)\n            .map_err(|e| anyhow::anyhow!(\"Python on_time_event failed: {e}\"))\n    }\n\n    fn on_signal(&mut self, signal: &Signal) -> anyhow::Result<()> {\n        self.dispatch_on_signal(signal)\n            .map_err(|e| anyhow::anyhow!(\"Python on_signal failed: {e}\"))\n    }\n\n    fn on_queue_state(&mut self, event: &QueueStateChanged) -> anyhow::Result<()> {\n        self.dispatch_on_queue_state(event)\n            .map_err(|e| anyhow::anyhow!(\"Python on_queue_state failed: {e}\"))\n    }\n\n    fn on_socket_state(&mut self, event: &SocketStateChanged) -> anyhow::Result<()> {\n        self.dispatch_on_socket_state(event)\n            .map_err(|e| anyhow::anyhow!(\"Python on_socket_state failed: {e}\"))\n    }\n}\n\n#[pyo3::pymethods]\n#[pyo3_stub_gen::derive::gen_stub_pymethods]\n#[allow(\n    clippy::large_types_passed_by_value,\n    reason = \"PyO3 callbacks accept Python-owned event values\"","sourceCodeStart":573,"sourceCodeEnd":609,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/trading/src/python/algorithm.rs#L573-L609","documentation":"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}\")`.","triggerScenarios":"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.","commonSituations":"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.","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:`"],"exampleFix":"# before\ndef on_signal(self, signal):\n    payload = json.loads(signal.data.value)[\"target\"]  # KeyError on malformed signal\n\n# after\ndef on_signal(self, signal):\n    try:\n        payload = json.loads(signal.data.value).get(\"target\")\n    except (ValueError, AttributeError) as e:\n        self.log.error(f\"Bad signal {signal.topic}: {e}\")\n        return\n    if payload is None:\n        return","handlingStrategy":"validation","validationCode":"def safe_on_signal(signal):\n    raw = getattr(signal, 'data', None)\n    return raw is not None  # validate before parsing in on_signal","typeGuard":"def is_parseable_signal(signal):\n    data = getattr(signal, 'data', None)\n    return data is not None and hasattr(data, 'value')","tryCatchPattern":"try:\n    algo.on_signal(signal)\nexcept Exception as e:\n    log.error(f\"on_signal failed for topic '{getattr(signal, 'topic', '?')}': {e}\")","preventionTips":["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"],"tags":["python","callback","signal","rust","execution-algorithm"],"backgroundTag":"api-error-response","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}