{"record":{"id":"e876db3221e373b0","repo":"nautechsystems/nautilus_trader","slug":"python-simulationmodule-log-diagnostics-failed-e","errorCode":null,"errorMessage":"Python SimulationModule.log_diagnostics failed: {e}","messagePattern":"Python SimulationModule\\.log_diagnostics failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/python/modules.rs","lineNumber":316,"sourceCode":"\n    fn acknowledge(&self, outcomes: &[AccountAdjustmentOutcome]) -> anyhow::Result<()> {\n        Python::attach(|py| -> anyhow::Result<()> {\n            let outcomes = outcomes\n                .iter()\n                .map(PyAccountAdjustmentOutcome::from)\n                .collect::<Vec<_>>();\n            self.obj.bind(py).call_method1(\"acknowledge\", (outcomes,))?;\n            Ok(())\n        })\n        .map_err(|e| anyhow::anyhow!(\"Python SimulationModule.acknowledge failed: {e}\"))\n    }\n\n    fn log_diagnostics(&self) -> anyhow::Result<()> {\n        Python::attach(|py| -> anyhow::Result<()> {\n            self.obj.bind(py).call_method0(\"log_diagnostics\")?;\n            Ok(())\n        })\n        .map_err(|e| anyhow::anyhow!(\"Python SimulationModule.log_diagnostics failed: {e}\"))\n    }\n\n    fn reset(&self) -> anyhow::Result<()> {\n        Python::attach(|py| -> anyhow::Result<()> {\n            self.obj.bind(py).call_method0(\"reset\")?;\n            Ok(())\n        })\n        .map_err(|e| anyhow::anyhow!(\"Python SimulationModule.reset failed: {e}\"))\n    }\n}\n\nfn pyobject_to_builtin_simulation_module_any(\n    obj: &Bound<'_, PyAny>,\n) -> Option<SimulationModuleAny> {\n    if let Ok(module) = obj.extract::<PyRef<'_, CfdSwapModule>>() {\n        return Some(SimulationModuleAny::CfdSwap((*module).clone()));\n    }\n","sourceCodeStart":298,"sourceCodeEnd":334,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/python/modules.rs#L298-L334","documentation":"Calling the Python SimulationModule object's log_diagnostics method raised a Python exception; the Rust wrapper propagates it as an anyhow error so the backtest module diagnostics step fails with the underlying Python error message.","triggerScenarios":"Engine diagnostics invocation (e.g. at halt/teardown or on request) where the Python module's log_diagnostics() raises, typically while formatting module state.","commonSituations":"Diagnostics code assuming internal attributes exist when they were never populated (e.g. empty books, missing counters) raising AttributeError/KeyError.","solutions":["Fix the exception in the Python module's log_diagnostics per the traceback.","Use getattr(..., default)/dict.get so diagnostics never fail on absent state.","Wrap diagnostics formatting so it degrades gracefully when state is empty."],"exampleFix":"# before\ndef log_diagnostics(self):\n    print(self.counts['ticks'])  # KeyError\n# after\ndef log_diagnostics(self):\n    print(self.counts.get('ticks', 0))","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"def log_diagnostics(self):\n    try:\n        print(self.counts.get('ticks', 0))\n    except Exception:\n        logging.exception(\"log_diagnostics failed\")  # never let diagnostics break the run\n","preventionTips":["Diagnostics code must never raise: use .get()/getattr defaults everywhere.","Format state defensively — assume any attribute may be unpopulated.","Call log_diagnostics manually in tests to verify it is safe."],"tags":["python","backtest","simulation-module","diagnostics"],"backgroundTag":"upstream-api-error","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"}