{"record":{"id":"d7d425524115060b","repo":"nautechsystems/nautilus_trader","slug":"python-on-dispose-failed-e","errorCode":null,"errorMessage":"Python on_dispose failed: {e}","messagePattern":"Python on_dispose failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/python/actor.rs","lineNumber":1040,"sourceCode":"\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<()> {\n        self.dispatch_on_fault()\n            .map_err(|e| anyhow::anyhow!(\"Python on_fault failed: {e}\"))\n    }\n\n    fn on_save(&self) -> anyhow::Result<IndexMap<String, Vec<u8>>> {\n        self.dispatch_on_save()\n            .map_err(|e| anyhow::anyhow!(\"Python on_save failed: {e}\"))\n    }\n\n    fn on_load(&mut self, state: IndexMap<String, Vec<u8>>) -> anyhow::Result<()> {","sourceCodeStart":1022,"sourceCodeEnd":1058,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/python/actor.rs#L1022-L1058","documentation":"Raised by the Rust `DataActor` bridge when the Python actor's `on_dispose()` callback raises. `dispatch_on_dispose()` propagates the Python exception and it is rewrapped as this anyhow error. Dispose is the final teardown hook after stop, so failures here happen during component destruction.","triggerScenarios":"Any exception in the user's Python `on_dispose`: freeing resources already freed, double-closing connections, or referencing members cleaned up in on_stop that ran earlier in teardown.","commonSituations":"Shutdown of a live node where dispose closes a socket already closed in on_stop; deleting temp files that no longer exist; accessing a client set to None during teardown.","solutions":["Check the embedded Python traceback for the exact raise site in on_dispose.","Make dispose idempotent: guard closes/deletes with checks or try/except and log instead of raising.","Ensure on_dispose does not depend on state that on_stop already released.","Test full stop->dispose teardown to confirm cleanup is safe to run twice."],"exampleFix":"// before (Python)\ndef on_dispose(self):\n    self.socket.close()\n\n// after\ndef on_dispose(self):\n    if self.socket is not None:\n        try:\n            self.socket.close()\n        finally:\n            self.socket = None","handlingStrategy":"try-catch","validationCode":"# ensure teardown targets still exist before dispose\nassert self.socket is not None or getattr(self, 'socket', None) is None, 'socket state inconsistent'","typeGuard":"def closable(res):\n    return res is not None and hasattr(res, 'close')","tryCatchPattern":"def on_dispose(self):\n    try:\n        ...  # final teardown\n    except Exception as e:\n        self.log.error(f\"on_dispose failed: {e}\")\n    finally:\n        self.socket = None","preventionTips":["Make on_dispose idempotent — safe to call after on_stop already cleaned up.","Use try/finally so references are cleared even if close fails.","Never depend in dispose on state released in earlier lifecycle stages.","Exercise full stop->dispose in integration tests."],"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-14T00:17:10.932Z"}