{"record":{"id":"6ed9d66109d787b1","repo":"nautechsystems/nautilus_trader","slug":"python-on-historical-data-failed-e-6ed9d6","errorCode":null,"errorMessage":"Python on_historical_data failed: {e}","messagePattern":"Python on_historical_data failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/trading/src/python/strategy.rs","lineNumber":1218,"sourceCode":"            .map_err(|e| anyhow::anyhow!(\"Python on_option_greeks failed: {e}\"))\n    }\n\n    fn on_option_chain(&mut self, slice: &OptionChainSlice) -> anyhow::Result<()> {\n        self.dispatch_on_option_chain(slice)\n            .map_err(|e| anyhow::anyhow!(\"Python on_option_chain failed: {e}\"))\n    }\n\n    fn on_historical_data(&mut self, data: &dyn Any) -> anyhow::Result<()> {\n        Python::attach(|py| {\n            let py_data: Py<PyAny> = if let Some(custom_data) = data.downcast_ref::<CustomData>() {\n                Py::new(py, custom_data.clone())?.into_any()\n            } else if let Some(custom_data) = data.downcast_ref::<Vec<CustomData>>() {\n                custom_data.clone().into_py_any(py)?\n            } else {\n                anyhow::bail!(\"Failed to convert historical data to Python: unsupported type\");\n            };\n            self.dispatch_on_historical_data(py_data)\n                .map_err(|e| anyhow::anyhow!(\"Python on_historical_data failed: {e}\"))\n        })\n    }\n\n    fn on_historical_book_deltas(&mut self, deltas: &[OrderBookDelta]) -> anyhow::Result<()> {\n        self.dispatch_on_historical_book_deltas(deltas.to_vec())\n            .map_err(|e| anyhow::anyhow!(\"Python on_historical_book_deltas failed: {e}\"))\n    }\n\n    fn on_historical_book_depth(&mut self, depths: &[OrderBookDepth10]) -> anyhow::Result<()> {\n        self.dispatch_on_historical_book_depth(depths.to_vec())\n            .map_err(|e| anyhow::anyhow!(\"Python on_historical_book_depth failed: {e}\"))\n    }\n\n    fn on_historical_quotes(&mut self, quotes: &[QuoteTick]) -> anyhow::Result<()> {\n        self.dispatch_on_historical_quotes(quotes.to_vec())\n            .map_err(|e| anyhow::anyhow!(\"Python on_historical_quotes failed: {e}\"))\n    }\n","sourceCodeStart":1200,"sourceCodeEnd":1236,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/trading/src/python/strategy.rs#L1200-L1236","documentation":"Raised when the strategy's Python `on_historical_data` handler throws after the Rust bridge successfully converted the payload to a Python object. `dispatch_on_historical_data` calls the Python method via PyO3 and any exception is re-wrapped with this anyhow message. The root cause is an unhandled exception in the user's Python handler.","triggerScenarios":"Historical data (CustomData payload) is delivered and the strategy's `on_historical_data(self, data)` raises — e.g. expecting a different payload shape, unpacking fields that don't exist, or errors in warm-up/backfill logic.","commonSituations":"Handlers written for one custom data payload version but receiving another; `.unwrap()`/attribute access on the custom data object; historical request configs changed between runs.","solutions":["Read the chained Python traceback in `e` and fix `on_historical_data`","Validate the payload type/shape inside the handler (check `data.data_type` / attributes before use)","Confirm the data type string registered for the request matches what the handler expects","Add a try/except inside the handler for non-fatal warm-up data"],"exampleFix":"// before (Python)\ndef on_historical_data(self, data):\n    rows = data.payload  # AttributeError: payload renamed\n// after\ndef on_historical_data(self, data):\n    rows = getattr(data, 'payload', None) or getattr(data, 'value', None)","handlingStrategy":"type-guard","validationCode":"def payload_ok(data):\n    return data is not None and (hasattr(data, 'value') or hasattr(data, 'payload'))","typeGuard":"def usable_historical_payload(data):\n    return data is not None and hasattr(data, 'data_type') and data.value is not None","tryCatchPattern":"try:\n    strategy.on_historical_data(data)\nexcept Exception as e:\n    strategy.log.error(f\"on_historical_data failed: {e}\", exc_info=True)","preventionTips":["Verify the registered data_type string matches what the handler expects to unpack","Use getattr with defaults for evolving custom payload schemas","Keep request configs and handler parsing in sync","Unit test warm-up with the exact payload class registered in the request"],"tags":["rust","python","nautilustrader","callback","historical-data"],"backgroundTag":"python-callback-exception","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}