nautechsystems/nautilus_trader · critical

Invalid `LiquiditySide`

Error message

Invalid `LiquiditySide`

What it means

While hydrating the optional `liquidity_side` column, `LiquiditySide::from_str` result is unwrapped with expect(). The panic means a non-NULL liquidity_side value in the row (expected 'MAKER'/'TAKER'/'NONE') is not a valid LiquiditySide, so the order row fails to load.

Source

Thrown at crates/infrastructure/src/sql/models/orders.rs:1103

            .ok()
            .and_then(|x| x.and_then(|s| Decimal::from_str(s).ok()));
        let trailing_offset_type = row
            .try_get::<Option<TrailingOffsetTypePg>, _>("trailing_offset_type")
            .ok()
            .flatten()
            .and_then(|value| value.0);
        let time_in_force = row
            .try_get::<&str, _>("time_in_force")
            .map(|x| TimeInForce::from_str(x).expect("Invalid `TimeInForce`"))?;
        let expire_time = row
            .try_get::<Option<&str>, _>("expire_time")
            .ok()
            .and_then(|x| x.map(UnixNanos::from));
        let filled_qty = row.try_get::<&str, _>("filled_qty").map(Quantity::from)?;
        let liquidity_side = row
            .try_get::<Option<&str>, _>("liquidity_side")
            .ok()
            .and_then(|x| x.map(|x| LiquiditySide::from_str(x).expect("Invalid `LiquiditySide`")));
        let avg_px = row.try_get::<Option<Decimal>, _>("avg_px").ok().flatten();
        let slippage = row.try_get::<Option<Decimal>, _>("slippage").ok().flatten();
        let commissions = row
            .try_get::<Option<Vec<String>>, _>("commissions")?
            .map_or_else(Vec::new, |c| {
                c.into_iter().map(|s| Money::from(&s)).collect()
            });
        let status = row
            .try_get::<&str, _>("status")
            .map(|x| OrderStatus::from_str(x).expect("Invalid `OrderStatus`"))?;
        let is_post_only = row.try_get::<bool, _>("is_post_only")?;
        let is_reduce_only = row.try_get::<bool, _>("is_reduce_only")?;
        let is_quote_quantity = row.try_get::<bool, _>("is_quote_quantity")?;
        let display_qty = row
            .try_get::<Option<&str>, _>("display_qty")
            .ok()
            .and_then(|x| x.map(Quantity::from));
        let emulation_trigger = row

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Audit the column: `SELECT DISTINCT liquidity_side FROM orders WHERE liquidity_side IS NOT NULL` and fix offending values
  2. Persist canonical LiquiditySide strings from the writer path
  3. Normalize values (trim/upper) in a migration if that is the only mismatch
  4. Map the parse failure into an error instead of expect when reading external data

Example fix

// before
x.map(|x| LiquiditySide::from_str(x).expect("Invalid `LiquiditySide`"))
// after
x.map(|x| LiquiditySide::from_str(x).map_err(|e| ModelError::Parse(format!("invalid liquidity_side '{x}': {e}")))).transpose()?
Defensive patterns

Strategy: type-guard

Validate before calling

fn valid_liquidity_side(s: Option<&str>) -> bool {
    s.map(|s| LiquiditySide::from_str(s).is_ok()).unwrap_or(true)
}

Type guard

fn is_known_liquidity_side(s: &str) -> bool {
    LiquiditySide::from_str(s).is_ok()
}

Try / catch

let liquidity_side = x
    .map(|x| LiquiditySide::from_str(x)
        .map_err(|e| ModelError::Parse(format!("row {}: invalid liquidity_side '{x}': {e}", row_id))))
    .transpose()?;

Prevention

When it happens

Trigger: Calling `OrderModel::from_row` on a row whose `liquidity_side` contains an unrecognized string (wrong case like 'maker' if the parser is case-sensitive, abbreviations 'M'/'T', or values from another system).

Common situations: Data imported from exchange reports or third-party databases using different liquidity naming; mixed-version writers; manual updates.

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/24cb415dcab8ef30. Report an issue: GitHub.