{"record":{"id":"e0a09548dc5d5314","repo":"nautechsystems/nautilus_trader","slug":"commission-calculation-overflow","errorCode":null,"errorMessage":"commission calculation overflow","messagePattern":"commission calculation overflow","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/execution/src/models/fee.rs","lineNumber":326,"sourceCode":"}\n\nimpl PerContractFeeModel {\n    /// Creates a new [`PerContractFeeModel`] instance.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if `commission` is negative.\n    pub fn new(commission: Money) -> anyhow::Result<Self> {\n        if commission.raw < 0 {\n            anyhow::bail!(\"Commission must be greater than or equal to zero\")\n        }\n        Ok(Self { commission })\n    }\n}\n\nfn mul_checked(lhs: Decimal, rhs: Decimal) -> anyhow::Result<Decimal> {\n    lhs.checked_mul(rhs)\n        .ok_or_else(|| anyhow::anyhow!(\"commission calculation overflow\"))\n}\n\nimpl FeeModel for PerContractFeeModel {\n    fn get_commission(\n        &self,\n        _order: &OrderAny,\n        fill_quantity: Quantity,\n        _fill_px: Price,\n        instrument: &InstrumentAny,\n    ) -> anyhow::Result<Money> {\n        let contracts = spread_contract_count(instrument)?;\n        let total = mul_checked(self.commission.as_decimal(), fill_quantity.as_decimal())\n            .and_then(|v| mul_checked(v, contracts))?;\n        Money::from_decimal(total, self.commission.currency).map_err(Into::into)\n    }\n}\n\nfn spread_contract_count(instrument: &InstrumentAny) -> anyhow::Result<Decimal> {","sourceCodeStart":308,"sourceCodeEnd":344,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/execution/src/models/fee.rs#L308-L344","documentation":"Fee models compute commissions with `Decimal` arithmetic. `mul_checked` wraps `Decimal::checked_mul` and raises this error when multiplying the rate by a quantity/price (or similar factors) would overflow the Decimal representation. It is a guard against silently producing an invalid commission.","triggerScenarios":"Calling `get_commission`/`get_commission_with_context` on a fee model (e.g. PerContractFeeModel, capped option fee model) with extreme fill quantities, prices, multipliers, or cap values whose product exceeds Decimal range.","commonSituations":"Instruments with enormous multipliers, malformed fill data (astronomical quantity), or a misconfigured fee cap/rate; running backtests on synthetic data with unbounded values.","solutions":["Validate fill quantity, fill price, and instrument multiplier are sane before computing commission.","Reduce/fix the fee model parameters (rate, cap) that produce overflow-sized products.","If legitimately large values are needed, scale the computation or use a wider numeric representation upstream."],"exampleFix":"// before: unchecked inputs\nlet fee = model.get_commission(&order, qty, px, &instrument)?;\n// after: pre-validate magnitudes\nassert!(qty.as_decimal() < Decimal::MAX / instrument.multiplier().as_decimal());\nlet fee = model.get_commission(&order, qty, px, &instrument)?;","handlingStrategy":"validation","validationCode":"assert qty.as_decimal() > Decimal::ZERO && qty.as_decimal() < Decimal::from(1_000_000)\nassert instrument.multiplier().as_decimal() < Decimal::MAX / px.as_decimal()","typeGuard":null,"tryCatchPattern":"match model.get_commission(&order, qty, px, &instrument) {\n    Ok(fee) => fee,\n    Err(e) if e.to_string().contains(\"overflow\") => Money::zero(currency),\n}","preventionTips":["Sanity-check fill quantities and prices before fee computation.","Keep fee rates and caps within realistic bounds in configuration.","Use checked arithmetic everywhere around Decimal commission math."],"tags":["decimal","overflow","fee","commission","rust"],"backgroundTag":"value-out-of-range","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"}