nautechsystems/nautilus_trader · error
Python on_reset failed: {e}
Error message
Python on_reset failed: {e} What it means
This error wraps any Python exception raised by the strategy's user-implemented `on_reset()` callback. The Rust `DataActor::on_reset` dispatches to the Python instance via `call_method0(py, "on_reset")` (crates/trading/src/python/strategy.rs:356-361) and re-wraps any `PyErr` as `anyhow::anyhow!("Python on_reset failed: {e}")`. Reset is used to return the actor to a clean state (e.g. between backtest runs), so a failure here can poison subsequent runs with stale state.
Source
Thrown at crates/trading/src/python/strategy.rs:1076
fn on_start(&mut self) -> anyhow::Result<()> {
Strategy::on_start(self)?;
self.dispatch_on_start()
.map_err(|e| anyhow::anyhow!("Python on_start failed: {e}"))
}
fn on_stop(&mut self) -> anyhow::Result<()> {
self.dispatch_on_stop()
.map_err(|e| anyhow::anyhow!("Python on_stop failed: {e}"))
}
fn on_resume(&mut self) -> anyhow::Result<()> {
self.dispatch_on_resume()
.map_err(|e| anyhow::anyhow!("Python on_resume failed: {e}"))
}
fn on_reset(&mut self) -> anyhow::Result<()> {
self.dispatch_on_reset()
.map_err(|e| anyhow::anyhow!("Python on_reset failed: {e}"))
}
fn on_dispose(&mut self) -> anyhow::Result<()> {
self.dispatch_on_dispose()
.map_err(|e| anyhow::anyhow!("Python on_dispose failed: {e}"))
}
fn on_degrade(&mut self) -> anyhow::Result<()> {
self.dispatch_on_degrade()
.map_err(|e| anyhow::anyhow!("Python on_degrade failed: {e}"))
}
fn on_fault(&mut self) -> anyhow::Result<()> {
self.dispatch_on_fault()
.map_err(|e| anyhow::anyhow!("Python on_fault failed: {e}"))
}
fn on_save(&self) -> anyhow::Result<IndexMap<String, Vec<u8>>> {View on GitHub (pinned to 18893faf8b)
Solutions
- Read the chained Python traceback to find the raising line in `on_reset`.
- Initialize all resettable attributes in `__init__` (e.g. `self._orders = {}`) so reset can safely clear them.
- Use tolerant clears (`dict.pop`, `getattr` with defaults, `contextlib.suppress`) in `on_reset`.
- Make `on_reset` idempotent and test it in a start -> reset -> start cycle.
Example fix
// before (strategy.py)
def on_reset(self):
self.cache.delete(self._cache_key) # raises if never created
// after
def on_reset(self):
self._orders = {}
self.cache.delete(self._cache_key) if self.cache.check(self._cache_key) else None Defensive patterns
Strategy: try-catch
Validate before calling
# before reset in a backtest loop
missing = [a for a in ("_orders", "_positions") if not hasattr(strategy, a)]
assert not missing, f"uninitialized resettable attrs: {missing}" Type guard
def safely_reset(obj, attr, default):
if hasattr(obj, attr):
setattr(obj, attr, default) Try / catch
def on_reset(self):
with contextlib.suppress(Exception):
self.cache.delete(self._cache_key)
self._orders = {}
self._last_event_ts = None Prevention
- Initialize all resettable attributes in `__init__` so reset never touches unset state.
- Make `on_reset` idempotent and safe to call on a never-started strategy.
- Run backtests in loops during development so reset bugs surface early.
- Prefer tolerant clears (dict.pop, suppress, hasattr checks) over hard failures in reset.
When it happens
Trigger: Calling `strategy.reset()` (engine reset, backtest re-run, or post-fault recovery) when the Python subclass's `on_reset()` raises: e.g. clearing state containers that were never initialized, releasing resources already released, or any bug in user reset logic.
Common situations: Backtest loops where the second run's `on_reset` hits state assumptions from the first run, deleting files or keys that don't exist, or resetting attributes that were never set because the strategy never started.
Related errors
- Python on_reset failed: {e}
- Python on_start failed: {e}
- Python on_stop failed: {e}
- Python on_resume failed: {e}
- Python on_dispose failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e21013e04ef663bd.
Report an issue: GitHub.