nautechsystems/nautilus_trader · error

Invalid `LiquiditySide`: {liquidity_side}

Error message

Invalid `LiquiditySide`: {liquidity_side}

What it means

`base_calculate_commission` maps the trade's `LiquiditySide` to maker or taker fees. `LiquiditySide::NoLiquiditySide` carries no fee rate, so a commission cannot be computed and the method bails naming the liquidity side. Commission calculation requires the order to have been recorded as maker or taker.

Source

Thrown at crates/model/src/accounts/base.rs:403

    pub fn base_calculate_commission(
        &self,
        instrument: &InstrumentAny,
        last_qty: Quantity,
        last_px: Price,
        liquidity_side: LiquiditySide,
        use_quote_for_inverse: Option<bool>,
    ) -> anyhow::Result<Money> {
        anyhow::ensure!(
            liquidity_side != LiquiditySide::NoLiquiditySide,
            "Invalid `LiquiditySide`: {liquidity_side}"
        );
        let notional =
            instrument.try_calculate_notional_value(last_qty, last_px, use_quote_for_inverse)?;
        let rate = match liquidity_side {
            LiquiditySide::Maker => instrument.maker_fee(),
            LiquiditySide::Taker => instrument.taker_fee(),
            LiquiditySide::NoLiquiditySide => {
                anyhow::bail!("Invalid `LiquiditySide`: {liquidity_side}")
            }
        };
        let commission = notional
            .as_decimal()
            .checked_mul(rate)
            .ok_or_else(|| anyhow::anyhow!("commission calculation overflow"))?;

        Ok(Money::from_decimal(commission, notional.currency)?)
    }
}

/// Updates the locked balance for the given instrument and currency, then recalculates the
/// account balance for that currency from all per-(instrument, currency) locks.
///
/// The reservation is recorded without a balance when the currency has no observed balance yet,
/// so a later balance report derives from it.
///
/// # Errors

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Only call commission calculation on `OrderFilled` events where liquidity_side is Maker or Taker.
  2. Set liquidity_side explicitly when constructing fills (from venue data or fill model in backtests).
  3. Check the venue/data adapter populates the liquidity side field.
  4. Skip/short-circuit NoLiquiditySide events in your fee aggregation loop before calling the API.

Example fix

// before
let fee = account.calculate_commission(&instrument, &order.last_event(), qty, px)?;
// after
if order.last_event().liquidity_side() != LiquiditySide::NoLiquiditySide {
    let fee = account.calculate_commission(&instrument, &order.last_event(), qty, px)?;
}
Defensive patterns

Strategy: type-guard

Validate before calling

if event.liquidity_side() == LiquiditySide::NoLiquiditySide {
    // skip commission calculation; no fee determinable
} else {
    let fee = account.calculate_commission(&instrument, &event, last_qty, last_px)?;
}

Type guard

fn has_fee_side(side: LiquiditySide) -> bool {
    matches!(side, LiquiditySide::Maker | LiquiditySide::Taker)
}

Try / catch

match account.calculate_commission(&instrument, &event, qty, px) {
    Err(e) if e.to_string().contains("Invalid `LiquiditySide`") => {
        log::warn!("event has NoLiquiditySide; skipping fee");
    }
    r => r?,
}

Prevention

When it happens

Trigger: Calling `calculate_commission` on an account/instrument with an order event whose `liquidity_side` is `NoLiquiditySide` — e.g. passing an unfilled OrderInitialized/Submitted event, or constructing an OrderFilled without setting the liquidity side.

Common situations: Simulated fills in a backtest where the fill builder omitted liquidity_side, aggregating fees across an order's lifecycle including pre-fill events, or a venue adapter that doesn't populate liquidity side.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/daa299cf0b088535. Report an issue: GitHub.