{"record":{"id":"523899a6a4df0c2a","repo":"nautechsystems/nautilus_trader","slug":"liquidity-side-not-set","errorCode":null,"errorMessage":"Liquidity side not set","messagePattern":"Liquidity side not set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/polymarket/src/models.rs","lineNumber":68,"sourceCode":"pub struct PolymarketFeeModel;\n\nimpl FeeModel for PolymarketFeeModel {\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 InstrumentAny::BinaryOption(binary) = instrument else {\n            anyhow::bail!(\"PolymarketFeeModel requires a binary option instrument\");\n        };\n\n        let liquidity_side = match order.liquidity_side() {\n            Some(LiquiditySide::Maker) => LiquiditySide::Maker,\n            Some(LiquiditySide::Taker) => LiquiditySide::Taker,\n            Some(LiquiditySide::NoLiquiditySide) | None => {\n                anyhow::bail!(\"Liquidity side not set\")\n            }\n        };\n\n        let Some(schedule) = binary\n            .info\n            .as_ref()\n            .and_then(|info| info.get(\"fee_schedule\"))\n            .map(|value| serde_json::from_value::<FeeSchedule>(value.clone()))\n            .transpose()\n            .context(\"invalid Polymarket fee schedule\")?\n        else {\n            return Ok(Money::zero(instrument.quote_currency()));\n        };\n\n        validate_schedule(&schedule)?;\n\n        let fill_price = fill_px.as_decimal();\n        if !(Decimal::ZERO..=Decimal::ONE).contains(&fill_price) {","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/polymarket/src/models.rs#L50-L86","documentation":"Polymarket fee calculation distinguishes maker vs taker fees, so the order must have a liquidity side set. If order.liquidity_side() returns None or NoLiquiditySide, get_commission cannot select the correct fee rate and bails with 'Liquidity side not set'.","triggerScenarios":"Computing commission for an order whose liquidity side was never assigned — e.g. calling get_commission before the fill event stamped LiquiditySide, or manually constructed order fixtures without liquidity_side.","commonSituations":"Backtests/tests where OrderFilled events are synthesized without setting liquidity_side; fee preview calls on resting-but-unfilled orders; engine versions where NoLiquiditySide is the default.","solutions":["Set order.liquidity_side (Maker or Taker) before requesting commission, typically from the fill/report event.","Only call get_commission in response to fill events that carry a liquidity side.","In tests/backtests, populate LiquiditySide explicitly when constructing fill events.","Default to Taker in caller code when the side is genuinely unknown, if that matches your business rules."],"exampleFix":"// before\nlet fee = fee_model.get_commission(&order, qty, px, &instrument)?;\n// after\nif order.liquidity_side().is_none_or(|s| s == LiquiditySide::NoLiquiditySide) {\n    log::warn!(\"liquidity side missing; skipping fee calc\");\n    return Ok(Money::zero(instrument.quote_currency()));\n}\nlet fee = fee_model.get_commission(&order, qty, px, &instrument)?;","handlingStrategy":"validation","validationCode":"if order.liquidity_side().is_none_or(|s| s == LiquiditySide::NoLiquiditySide) {\n    return Err(\"order has no liquidity side; cannot compute commission\".into());\n}","typeGuard":"fn has_liquidity_side(order: &OrderAny) -> bool {\n    matches!(order.liquidity_side(), Some(LiquiditySide::Maker) | Some(LiquiditySide::Taker))\n}","tryCatchPattern":"match fee_model.get_commission(&order, qty, px, &instrument) {\n    Ok(fee) => fee,\n    Err(e) if e.to_string() == \"Liquidity side not set\" => {\n        log::warn!(\"fill without liquidity side; defaulting taker fee\");\n        compute_taker_fee_fallback(qty, px, &instrument)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Set liquidity_side from every fill/execution report event.","Never synthesize fill events without a liquidity side in tests/backtests.","Only compute commission after fill confirmation, not on order submission."],"tags":["fees","polymarket","missing-field","orders"],"backgroundTag":"missing-required-argument","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"}