nautechsystems/nautilus_trader · error
Python on_historical_bars failed
Error message
Python on_historical_bars failed: {e} What it means
This error wraps any failure raised by a Python data actor's `on_historical_bars` callback when the Rust actor core dispatches historical bars into Python. It is a bridging error: the Rust side succeeded in collecting the bars, but the Python handler (or something it calls) raised an exception, which is converted into an anyhow error with this prefix.
Solutions
- Read the full chained error message: the `{e}` portion contains the original Python traceback/exception; fix the bug it reports in your Python actor's `on_historical_bars`.
- Verify your Python actor actually defines `on_historical_bars` with the expected signature and does not shadow it with an incompatible override.
- Validate bar data (non-empty, correct Bar type, expected instrument IDs) before replaying historical data.
- Run the handler logic standalone in Python with the same bars to reproduce and debug the exception quickly.
Example fix
// Python side — before (fragile handler)
def on_historical_bars(self, bars):
closes = [b.close for b in bars]
avg = sum(closes) / len(closes) # ZeroDivisionError if bars is empty
// after
def on_historical_bars(self, bars):
if not bars:
return
closes = [b.close for b in bars]
avg = sum(closes) / len(closes) Defensive patterns
Strategy: try-catch
Validate before calling
# Python assert callable(getattr(actor, 'on_historical_bars', None)), 'actor missing on_historical_bars' assert bars, 'no bars to replay'
Type guard
def has_bar_handler(actor) -> bool:
return callable(getattr(actor, 'on_historical_bars', None)) Try / catch
match actor.on_historical_bars(bars) {
Err(e) => { log::error!("historical bars dispatch failed: {e:#}"); /* halt replay or skip actor */ }
Ok(()) => {}
} Prevention
- Keep Python handler code exception-free by validating inputs at the top of each handler
- Test actors in pure Python against sample bars before Rust integration
- Never shadow built-in callbacks with incompatible signatures
When it happens
Trigger: Calling the actor's historical-data dispatch path (e.g. via `PyDataActor::on_historical_bars` in crates/common/src/python/actor.rs:1246) when the registered Python object's `on_historical_bars` method raises an exception — bad bar data assumptions, unhandled None, a bug in user Python code, or a missing/renamed callback method.
Common situations: Backtesting or historical-data replay where a user-defined Python strategy actor processes `Bar` objects and its handler contains a Python bug (attribute error, division by zero, incompatible indicator input), or the callback was renamed/overridden incorrectly in a subclass.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- Python on_historical_index_prices failed
- Python on_historical_mark_prices failed
- Failed to extract PyDataActor
- Python on_bar failed
- Python on_block failed
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c80df83aa938fe51.
Report an issue: GitHub.
Appendix: source
Thrown at crates/common/src/python/actor.rs:1246
.map_err(|e| anyhow::anyhow!("Python on_historical_quotes failed: {e}"))
}
fn on_historical_trades(&mut self, trades: &[TradeTick]) -> anyhow::Result<()> {
self.dispatch_on_historical_trades(trades.to_vec())
.map_err(|e| anyhow::anyhow!("Python on_historical_trades failed: {e}"))
}
fn on_historical_funding_rates(
&mut self,
funding_rates: &[FundingRateUpdate],
) -> anyhow::Result<()> {
self.dispatch_on_historical_funding_rates(funding_rates.to_vec())
.map_err(|e| anyhow::anyhow!("Python on_historical_funding_rates failed: {e}"))
}
fn on_historical_bars(&mut self, bars: &[Bar]) -> anyhow::Result<()> {
self.dispatch_on_historical_bars(bars.to_vec())
.map_err(|e| anyhow::anyhow!("Python on_historical_bars failed: {e}"))
}
fn on_historical_mark_prices(&mut self, mark_prices: &[MarkPriceUpdate]) -> anyhow::Result<()> {
self.dispatch_on_historical_mark_prices(mark_prices.to_vec())
.map_err(|e| anyhow::anyhow!("Python on_historical_mark_prices failed: {e}"))
}
fn on_historical_index_prices(
&mut self,
index_prices: &[IndexPriceUpdate],
) -> anyhow::Result<()> {
self.dispatch_on_historical_index_prices(index_prices.to_vec())
.map_err(|e| anyhow::anyhow!("Python on_historical_index_prices failed: {e}"))
}
}
#[pymethods]
#[pyo3_stub_gen::derive::gen_stub_pymethods]View on GitHub (pinned to 18893faf8b)