{"record":{"id":"1e1a06938e72e254","repo":"nautechsystems/nautilus_trader","slug":"python-on-historical-bars-failed-e-1e1a06","errorCode":null,"errorMessage":"Python on_historical_bars failed: {e}","messagePattern":"Python on_historical_bars failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/trading/src/python/strategy.rs","lineNumber":1252,"sourceCode":"            .map_err(|e| anyhow::anyhow!(\"Python on_historical_quotes failed: {e}\"))\n    }\n\n    fn on_historical_trades(&mut self, trades: &[TradeTick]) -> anyhow::Result<()> {\n        self.dispatch_on_historical_trades(trades.to_vec())\n            .map_err(|e| anyhow::anyhow!(\"Python on_historical_trades failed: {e}\"))\n    }\n\n    fn on_historical_funding_rates(\n        &mut self,\n        funding_rates: &[FundingRateUpdate],\n    ) -> anyhow::Result<()> {\n        self.dispatch_on_historical_funding_rates(funding_rates.to_vec())\n            .map_err(|e| anyhow::anyhow!(\"Python on_historical_funding_rates failed: {e}\"))\n    }\n\n    fn on_historical_bars(&mut self, bars: &[Bar]) -> anyhow::Result<()> {\n        self.dispatch_on_historical_bars(bars.to_vec())\n            .map_err(|e| anyhow::anyhow!(\"Python on_historical_bars failed: {e}\"))\n    }\n\n    fn on_historical_mark_prices(&mut self, mark_prices: &[MarkPriceUpdate]) -> anyhow::Result<()> {\n        self.dispatch_on_historical_mark_prices(mark_prices.to_vec())\n            .map_err(|e| anyhow::anyhow!(\"Python on_historical_mark_prices failed: {e}\"))\n    }\n\n    fn on_historical_index_prices(\n        &mut self,\n        index_prices: &[IndexPriceUpdate],\n    ) -> anyhow::Result<()> {\n        self.dispatch_on_historical_index_prices(index_prices.to_vec())\n            .map_err(|e| anyhow::anyhow!(\"Python on_historical_index_prices failed: {e}\"))\n    }\n}\n\nfn state_to_pydict(py: Python<'_>, state: &IndexMap<String, Vec<u8>>) -> PyResult<Py<PyDict>> {\n    let py_state = PyDict::new(py);","sourceCodeStart":1234,"sourceCodeEnd":1270,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/trading/src/python/strategy.rs#L1234-L1270","documentation":"This error wraps any failure while the Rust engine invokes the strategy's Python `on_historical_bars` callback with a batch of Bar objects. Conversion of each Bar to a Python object or an exception raised inside the user's Python handler is captured and re-raised as `Python on_historical_bars failed: {e}`.","triggerScenarios":"Historical bar data (e.g. from a request_bars response) is delivered to a Python strategy whose `on_historical_bars` override raises, or whose bars fail the Rust→Python conversion.","commonSituations":"User handler assumes a specific bar count or bar fields; calling indicators with wrong types; exceptions like KeyError/TypeError in the override; requesting bars for an instrument with no data and mishandling the empty list.","solutions":["Inspect the `{e}` message for the underlying Python exception raised in your `on_historical_bars` override and fix it.","Confirm the override signature `def on_historical_bars(self, bars)` matches exactly.","Handle the empty-bars case before processing.","Check that any indicators or types used in the handler accept the Bar objects passed."],"exampleFix":"// before\ndef on_historical_bars(self, bars):\n    self.fast.update(bars[-1])\n// after\ndef on_historical_bars(self, bars):\n    if not bars:\n        return\n    for bar in bars:\n        self.fast.update(bar)","handlingStrategy":"try-catch","validationCode":"def _safe_on_historical_bars(self, bars):\n    if bars is None or len(bars) == 0:\n        return\n    assert all(hasattr(b, 'open') and hasattr(b, 'close') for b in bars)","typeGuard":"def is_bar_list(obj):\n    return isinstance(obj, (list, tuple)) and all(hasattr(b, 'close') for b in obj)","tryCatchPattern":"def on_historical_bars(self, bars):\n    try:\n        for bar in bars:\n            self.indicators.update(bar)\n    except Exception as e:\n        self.log.error(f'Failed processing historical bars: {e}', exc_info=True)","preventionTips":["Guard indicator updates against empty bar batches","Keep the handler free of side effects that can raise (network, file I/O)","Test strategies with empty historical responses before live runs","Do not rename or shadow the on_historical_bars hook"],"tags":["python","callback","strategy","bars"],"backgroundTag":"unexpected-api-response-shape","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"}