{"record":{"id":"64a8e0e6ca0ff2a9","repo":"nautechsystems/nautilus_trader","slug":"python-on-historical-index-prices-failed-e-64a8e0","errorCode":null,"errorMessage":"Python on_historical_index_prices failed: {e}","messagePattern":"Python on_historical_index_prices failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/trading/src/python/strategy.rs","lineNumber":1265,"sourceCode":"            .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);\n    for (key, value) in state {\n        py_state.set_item(key, PyBytes::new(py, value))?;\n    }\n    Ok(py_state.unbind())\n}\n\nfn pydict_to_state(state: &Bound<'_, PyDict>) -> PyResult<IndexMap<String, Vec<u8>>> {\n    let mut rust_state = IndexMap::with_capacity(state.len());\n    for (key, value) in state.iter() {\n        rust_state.insert(key.extract()?, value.extract()?);\n    }\n    Ok(rust_state)\n}","sourceCodeStart":1247,"sourceCodeEnd":1283,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/trading/src/python/strategy.rs#L1247-L1283","documentation":"This error wraps any failure while the Rust engine invokes the strategy's Python `on_historical_index_prices` callback with a batch of IndexPriceUpdate objects. A failed Rust→Python conversion or an exception raised inside the user's Python handler is re-raised as `Python on_historical_index_prices failed: {e}`. This is the last of the historical-data callback wrappers before the impl block ends.","triggerScenarios":"Historical index-price data is delivered to a Python strategy whose `on_historical_index_prices` override raises an exception, or whose IndexPriceUpdate objects cannot be converted to Python.","commonSituations":"Handler code referencing wrong attribute names on index price updates; arithmetic on empty lists; mis-typed expectations of the update objects; exceptions from user indicators inside the override.","solutions":["Inspect `{e}` for the underlying Python exception in your `on_historical_index_prices` override and fix the handler.","Confirm the override signature `def on_historical_index_prices(self, index_prices)` is exact.","Handle empty update lists explicitly.","Ensure any objects used in the handler accept the IndexPriceUpdate values passed."],"exampleFix":"// before\ndef on_historical_index_prices(self, index_prices):\n    avg = sum(ip.index_price for ip in index_prices) / len(index_prices)  # ZeroDivisionError\n// after\ndef on_historical_index_prices(self, index_prices):\n    if not index_prices:\n        return None\n    return sum(ip.index_price for ip in index_prices) / len(index_prices)","handlingStrategy":"try-catch","validationCode":"def _safe_on_historical_index_prices(self, index_prices):\n    if index_prices is None or len(index_prices) == 0:\n        return\n    assert all(hasattr(ip, 'index_price') for ip in index_prices)","typeGuard":"def is_index_price_update_list(obj):\n    return isinstance(obj, (list, tuple)) and all(hasattr(ip, 'index_price') for ip in obj)","tryCatchPattern":"def on_historical_index_prices(self, index_prices):\n    try:\n        self._update_index_prices(index_prices)\n    except Exception as e:\n        self.log.error(f'Failed processing index prices: {e}', exc_info=True)","preventionTips":["Avoid division by unvalidated list lengths","Match the exact hook name on_historical_index_prices","Validate adapter data shapes before historical requests","Isolate processing logic so failures are logged, not raised to the engine"],"tags":["python","callback","strategy","index-price"],"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"}