{"record":{"id":"faf5109ba2e0b509","repo":"nautechsystems/nautilus_trader","slug":"python-on-resume-failed-e-faf510","errorCode":null,"errorMessage":"Python on_resume failed: {e}","messagePattern":"Python on_resume failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/trading/src/python/strategy.rs","lineNumber":1071,"sourceCode":"        let _ = self.dispatch_on_position_closed(event);\n    }\n}\n\nimpl DataActor for PyStrategyInner {\n    fn on_start(&mut self) -> anyhow::Result<()> {\n        Strategy::on_start(self)?;\n        self.dispatch_on_start()\n            .map_err(|e| anyhow::anyhow!(\"Python on_start failed: {e}\"))\n    }\n\n    fn on_stop(&mut self) -> anyhow::Result<()> {\n        self.dispatch_on_stop()\n            .map_err(|e| anyhow::anyhow!(\"Python on_stop failed: {e}\"))\n    }\n\n    fn on_resume(&mut self) -> anyhow::Result<()> {\n        self.dispatch_on_resume()\n            .map_err(|e| anyhow::anyhow!(\"Python on_resume failed: {e}\"))\n    }\n\n    fn on_reset(&mut self) -> anyhow::Result<()> {\n        self.dispatch_on_reset()\n            .map_err(|e| anyhow::anyhow!(\"Python on_reset failed: {e}\"))\n    }\n\n    fn on_dispose(&mut self) -> anyhow::Result<()> {\n        self.dispatch_on_dispose()\n            .map_err(|e| anyhow::anyhow!(\"Python on_dispose failed: {e}\"))\n    }\n\n    fn on_degrade(&mut self) -> anyhow::Result<()> {\n        self.dispatch_on_degrade()\n            .map_err(|e| anyhow::anyhow!(\"Python on_degrade failed: {e}\"))\n    }\n\n    fn on_fault(&mut self) -> anyhow::Result<()> {","sourceCodeStart":1053,"sourceCodeEnd":1089,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/trading/src/python/strategy.rs#L1053-L1089","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (strategy.py)\ndef on_resume(self):\n    self.subscribe_quote_ticks(self._instrument.id)  # _instrument may be stale/None\n\n// after\ndef on_resume(self):\n    instrument = self.cache.instrument(self._instrument_id)\n    if instrument is None:\n        self.log.error(f\"Instrument {self._instrument_id} unavailable; cannot resume\")\n        return\n    self.subscribe_quote_ticks(instrument.id)","handlingStrategy":"try-catch","validationCode":"# before calling resume\ninstrument = strategy.cache.instrument(strategy._instrument_id)\nassert instrument is not None, \"instrument missing from cache; cannot resume\"","typeGuard":"def resumable(strategy) -> bool:\n    return (\n        strategy._instrument_id is not None\n        and strategy.cache.instrument(strategy._instrument_id) is not None\n    )","tryCatchPattern":"def on_resume(self):\n    try:\n        self._resubscribe()\n    except Exception as e:\n        self.log.exception(f\"on_resume failed: {e}\")\n        self.degrade()  # fall back to degraded state instead of crashing","preventionTips":["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."],"tags":["python","strategy","lifecycle","on-resume"],"backgroundTag":"python-callback-raised","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}