nautechsystems/nautilus_trader · error
Python on_resume failed: {e}
Error message
Python on_resume failed: {e} What it means
This error wraps any Python exception raised by the strategy's user-implemented `on_resume()` callback. The Rust `DataActor::on_resume` dispatches to the Python instance via `call_method0(py, "on_resume")` (crates/trading/src/python/strategy.rs:349-354) and re-wraps any `PyErr` as `anyhow::anyhow!("Python on_resume failed: {e}")`. The strategy's transition from a degraded/paused state back to running is aborted.
Source
Thrown at crates/trading/src/python/strategy.rs:1071
let _ = self.dispatch_on_position_closed(event);
}
}
impl DataActor for PyStrategyInner {
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<()> {View on GitHub (pinned to 18893faf8b)
Solutions
- Read the chained Python traceback to locate the raising line in `on_resume`.
- Validate that resources needed on resume (subscriptions, instruments, clients) still exist before using them.
- Make `on_resume` re-establish state rather than assume it, e.g. re-derive subscriptions from current cache contents.
- Add a unit test covering the degrade -> resume cycle for your strategy.
Example fix
// before (strategy.py)
def on_resume(self):
self.subscribe_quote_ticks(self._instrument.id) # _instrument may be stale/None
// after
def on_resume(self):
instrument = self.cache.instrument(self._instrument_id)
if instrument is None:
self.log.error(f"Instrument {self._instrument_id} unavailable; cannot resume")
return
self.subscribe_quote_ticks(instrument.id) Defensive patterns
Strategy: try-catch
Validate before calling
# before calling resume instrument = strategy.cache.instrument(strategy._instrument_id) assert instrument is not None, "instrument missing from cache; cannot resume"
Type guard
def resumable(strategy) -> bool:
return (
strategy._instrument_id is not None
and strategy.cache.instrument(strategy._instrument_id) is not None
) Try / catch
def on_resume(self):
try:
self._resubscribe()
except Exception as e:
self.log.exception(f"on_resume failed: {e}")
self.degrade() # fall back to degraded state instead of crashing Prevention
- Re-derive resume state from the cache instead of trusting pre-degradation references.
- Test the degrade -> resume cycle explicitly in unit/integration tests.
- Never cache Python objects across lifecycle transitions; store IDs and re-fetch.
- Log and degrade gracefully instead of raising inside recovery paths.
When it happens
Trigger: Calling `strategy.resume()` (typically after `on_degrade` or a fault-recovery flow) when the Python subclass's `on_resume()` raises: e.g. re-subscribing with a stale/invalid bar type, touching resources released during degradation, or an unhandled exception in user resume logic.
Common situations: Recovery flows where resume logic assumes state that degradation tore down, resubscribing to instruments that were delisted or renamed, or resume handlers written but never exercised in tests.
Related errors
- Python on_resume failed: {e}
- Python on_start failed: {e}
- Python on_stop failed: {e}
- Python on_reset failed: {e}
- Python on_dispose failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/faf5109ba2e0b509.
Report an issue: GitHub.