{"record":{"id":"eca6cf3eaaa017c3","repo":"nautechsystems/nautilus_trader","slug":"python-on-stop-failed-e","errorCode":null,"errorMessage":"Python on_stop failed: {e}","messagePattern":"Python on_stop failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/python/actor.rs","lineNumber":1025,"sourceCode":"            if let Err(e) = algo.execute_exec_algorithm_command(command) {\n                log::error!(\"Error executing command on Python algorithm {actor_id}: {e}\");\n            }\n        } else {\n            log::error!(\"Python execution algorithm {actor_id} not found in registry\");\n        }\n    });\n    msgbus::register_any(endpoint.into(), handler);\n}\n\nimpl DataActor for PyDataActorInner {\n    fn on_start(&mut self) -> anyhow::Result<()> {\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<()> {","sourceCodeStart":1007,"sourceCodeEnd":1043,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/python/actor.rs#L1007-L1043","documentation":"This error is raised by the Rust `DataActor` bridge for Python actors (PyDataActorInner) when the user's Python `on_stop()` callback raises an exception. The Rust layer catches the Python error via `dispatch_on_stop()` and re-wraps it in an `anyhow::Error` with this message so the engine can surface it during component stop. The original Python traceback is embedded in `{e}`.","triggerScenarios":"Any exception raised inside a custom Python Actor/Strategy's `on_stop` method: calling unavailable clients or resources being torn down, accessing attributes deleted earlier in the stop sequence, or a typo raising AttributeError, etc.","commonSituations":"Strategies that flush state, close network connections, or cancel orders in on_stop and hit an already-closed resource; referencing a `self.cache` or client object that was released; typos in method names inside cleanup code.","solutions":["Read the embedded Python traceback in `{e}` to find the exact line in your on_stop that raised.","Make on_stop defensive: wrap fallible cleanup (network calls, order cancels) in try/except and log instead of raising.","Verify resources used in on_stop (clients, cache, connections) are still valid at stop time and not already disposed.","Run the strategy in isolation and call on_stop manually under a debugger to reproduce the failure."],"exampleFix":"// before (Python)\ndef on_stop(self):\n    self.client.close()\n    self.logger.info(self.last_price)\n\n// after\ndef on_stop(self):\n    try:\n        self.client.close()\n    except Exception as e:\n        self.log.error(f\"cleanup failed: {e}\")\n    self.logger.info(getattr(self, \"last_price\", None))","handlingStrategy":"try-catch","validationCode":"import inspect\nassert inspect.ismethod(actor.on_stop), \"on_stop must be a defined method\"\n# dry-run in a test harness: actor._log; call on_stop with stubbed clients before live stop","typeGuard":"def has_safe_on_stop(actor):\n    return callable(getattr(actor, 'on_stop', None))","tryCatchPattern":"def on_stop(self):\n    try:\n        ...  # cleanup logic\n    except Exception as e:\n        self.log.error(f\"on_stop cleanup failed: {e}\")","preventionTips":["Never let cleanup code raise: wrap every fallible call in on_stop with try/except.","Do not acquire new resources in on_stop; only release.","Keep a stop-path unit test that runs on_stop twice to prove idempotency.","Assert dependencies (clients, connections) are still valid before using them."],"tags":["python","actor-lifecycle","callback-exception","rust-bridge"],"backgroundTag":"python-callback-raised-exception","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"}