{"record":{"id":"ec6d303537fcd0e1","repo":"nautechsystems/nautilus_trader","slug":"e-ec6d30","errorCode":null,"errorMessage":"{e}","messagePattern":"\\{e\\}","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/execution/src/python/fill.rs","lineNumber":105,"sourceCode":"impl FillModel for PythonFillModel {\n    fn is_limit_filled(&mut self) -> anyhow::Result<bool> {\n        call_bool_method(&self.obj, \"is_limit_filled\")\n    }\n\n    fn is_slipped(&mut self) -> anyhow::Result<bool> {\n        call_bool_method(&self.obj, \"is_slipped\")\n    }\n\n    fn fill_limit_inside_spread(&self) -> anyhow::Result<bool> {\n        Python::attach(|py| -> anyhow::Result<bool> {\n            let obj = self.obj.bind(py);\n            if !obj.hasattr(\"fill_limit_inside_spread\")? {\n                return Ok(false);\n            }\n\n            obj.call_method0(\"fill_limit_inside_spread\")?\n                .extract()\n                .map_err(|e| anyhow::anyhow!(\"{e}\"))\n        })\n        .map_err(|e| anyhow::anyhow!(\"Python FillModel.fill_limit_inside_spread failed: {e}\"))\n    }\n\n    fn get_orderbook_for_fill_simulation(\n        &mut self,\n        instrument: &InstrumentAny,\n        order: &OrderAny,\n        best_bid: Price,\n        best_ask: Price,\n    ) -> anyhow::Result<Option<OrderBook>> {\n        Python::attach(|py| -> anyhow::Result<Option<OrderBook>> {\n            let obj = self.obj.bind(py);\n            if !obj.hasattr(\"get_orderbook_for_fill_simulation\")? {\n                return Ok(None);\n            }\n\n            let instrument = instrument_any_to_pyobject(py, instrument.clone())?;","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/execution/src/python/fill.rs#L87-L123","documentation":"When a Python FillModel's `fill_limit_inside_spread` method is called from Rust, the Python call or extraction of its boolean result failed. The raw Python error (`{e}`) is surfaced so the underlying Python-side failure is visible.","triggerScenarios":"Calling FillModel.fill_limit_inside_spread when the Python method raises an exception or does not return a value extractable to bool.","commonSituations":"A custom fill model returns None or a numpy bool instead of a plain bool; the Python method raises AttributeError on missing attributes; signature drift after a version upgrade.","solutions":["Read `{e}` for the underlying Python exception and fix the Python fill_limit_inside_spread implementation","Ensure the method takes no arguments and returns a plain Python bool","Confirm the object actually implements fill_limit_inside_spread (Rust skips the call if the attribute is absent, so it exists but misbehaved)","Add unit tests covering inside-spread limit order scenarios"],"exampleFix":"// before\ndef fill_limit_inside_spread(self):\n    return self.prob  # numpy float, extraction fails\n// after\ndef fill_limit_inside_spread(self):\n    return random.random() < self.prob  # plain bool","handlingStrategy":"type-guard","validationCode":"assert callable(getattr(fill_model, \"fill_limit_inside_spread\", None)), \"FillModel missing fill_limit_inside_spread\"","typeGuard":"def is_valid_fill_model(m) -> bool:\n    fn = getattr(m, \"fill_limit_inside_spread\", None)\n    return callable(fn)","tryCatchPattern":"let inside = match fill_model.fill_limit_inside_spread() {\n    Ok(b) => b,\n    Err(e) => { log::error!(\"fill model failed: {e:#}\"); false }\n};","preventionTips":["Return plain bools (not numpy bools or None) from fill model methods","Take no arguments in fill_limit_inside_spread","Unit-test the method for inside-spread scenarios"],"tags":["python-interop","fill-model","pyo3"],"backgroundTag":"type-mismatch","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"}