nautechsystems/nautilus_trader · error
{e}
Error message
{e} What it means
The Python fee model wrapper calls the user-provided Python object's `get_commission` via pyo3 and converts the result. The inner `map_err(|e| anyhow!("{e}"))` surfaces any pyo3 conversion/call error (Python exception or failed result extraction) with just the exception's text as this error message.
Source
Thrown at crates/execution/src/python/fee.rs:193
impl FeeModel for PythonFeeModel {
fn get_commission(
&self,
order: &OrderAny,
fill_quantity: Quantity,
fill_px: Price,
instrument: &InstrumentAny,
) -> anyhow::Result<Money> {
Python::attach(|py| -> anyhow::Result<Money> {
let order = order_any_to_pyobject(py, order.clone())?;
let instrument = instrument_any_to_pyobject(py, instrument.clone())?;
self.obj
.bind(py)
.call_method1(
"get_commission",
(order, fill_quantity, fill_px, instrument),
)?
.extract()
.map_err(|e| anyhow::anyhow!("{e}"))
})
.map_err(|e| anyhow::anyhow!("Python FeeModel.get_commission failed: {e}"))
}
fn get_commission_with_context(
&self,
order: &OrderAny,
fill_quantity: Quantity,
fill_px: Price,
instrument: &InstrumentAny,
underlying_px: Option<Price>,
) -> anyhow::Result<Money> {
Python::attach(|py| -> anyhow::Result<Money> {
let obj = self.obj.bind(py);
if !has_method_override_before_base(py, obj, "get_commission_with_context")? {
let order = order_any_to_pyobject(py, order.clone())?;
let instrument = instrument_any_to_pyobject(py, instrument.clone())?;
return objView on GitHub (pinned to 18893faf8b)
Solutions
- Read the wrapped `{e}` text — it is the original Python exception — and fix the Python fee model accordingly.
- Ensure the Python `get_commission(self, order, fill_quantity, fill_px, instrument)` signature matches exactly and returns a Money-compatible value.
- Test the Python model standalone with representative order/instrument objects to reproduce the exception.
Example fix
# before: wrong signature/return
def get_commission(self, order, qty, px):
return None
# after
def get_commission(self, order, fill_quantity, fill_px, instrument):
return Money(fill_quantity * fill_px * self.rate, instrument.quote_currency) Defensive patterns
Strategy: try-catch
Validate before calling
import inspect sig = inspect.signature(fee_model.get_commission) assert list(sig.parameters) == ['self', 'order', 'fill_quantity', 'fill_px', 'instrument']
Type guard
def is_valid_fee_model(obj) -> bool:
return callable(getattr(obj, 'get_commission', None)) and \
len(inspect.signature(obj.get_commission).parameters) == 4 Try / catch
try:
fee = fee_model.get_commission(order, qty, px, instrument)
except Exception as e:
logger.exception("FeeModel.get_commission failed: %s", e)
fee = None Prevention
- Match the exact Python method signature (order, fill_quantity, fill_px, instrument).
- Return a Money-compatible value, never None.
- Unit-test Python fee models standalone before wiring into the trading node.
- Log the full exception inside the Python model for root-cause visibility.
When it happens
Trigger: Calling `get_commission` on a Python FeeModel whose `get_commission` raises a Python exception, returns an object not extractable as the expected type, or accepts different arguments than `(order, fill_quantity, fill_px, instrument)`.
Common situations: Custom Python fee model with a wrong method signature; returning `None` or a non-Money value; exception inside user Python code (e.g. KeyError on instrument dict); passing objects not convertible between Rust/Python (version/type mismatch of bindings).
Related errors
- Python FeeModel.get_commission failed: {e}
- Failed to convert historical data to Python: unsupported typ
- Failed to convert instrument to Python: {e}
- Failed to convert batched deltas to Python: {e}
- Invalid book_snapshot_output: '{book_snapshot_output}'. Expe
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/36a601349fb8aa67.
Report an issue: GitHub.