nautechsystems/nautilus_trader · error

TrailingStopLimit order price not set

Error message

TrailingStopLimit order price not set

What it means

OrderAny::limit_px unwraps the Option<Price> on TrailingStopLimit orders; a trailing stop-limit only gets a concrete limit price once triggered/initialized with one, so calling limit_px while price is None panics with 'TrailingStopLimit order price not set'.

Source

Thrown at crates/model/src/orders/any.rs:319

    StopLimit(StopLimitOrder),
    TrailingStopLimit(TrailingStopLimitOrder),
    MarketOrderWithProtection(MarketOrder),
}

impl LimitOrderAny {
    /// Returns the limit price for this order.
    ///
    /// # Panics
    ///
    /// Panics if the `MarketToLimit` order price is not set.
    #[must_use]
    pub fn limit_px(&self) -> Price {
        match self {
            Self::Limit(order) => order.price,
            Self::MarketToLimit(order) => order.price.expect("MarketToLimit order price not set"),
            Self::StopLimit(order) => order.price,
            Self::TrailingStopLimit(order) => {
                order.price.expect("TrailingStopLimit order price not set")
            }
            Self::MarketOrderWithProtection(order) => {
                order.protection_price.expect("No price for order")
            }
        }
    }
}

impl PartialEq for LimitOrderAny {
    fn eq(&self, rhs: &Self) -> bool {
        match self {
            Self::Limit(order) => order.client_order_id == rhs.client_order_id(),
            Self::MarketToLimit(order) => order.client_order_id == rhs.client_order_id(),
            Self::StopLimit(order) => order.client_order_id == rhs.client_order_id(),
            Self::TrailingStopLimit(order) => order.client_order_id == rhs.client_order_id(),
            Self::MarketOrderWithProtection(order) => {
                order.client_order_id == rhs.client_order_id()
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure trailing stop-limit orders are created with a price (via builder .price(...)) when you intend to read limit_px later.
  2. Branch on the order variant and treat trailing stop-limit price as optional.
  3. Defer limit_px calls until the order has been activated and holds a price.

Example fix

// before
let px = order.limit_px(); // panics for TrailingStopLimit without price
// after
let px = if let OrderAny::TrailingStopLimit(o) = &order { o.price } else { Some(order.limit_px()) };
Defensive patterns

Strategy: type-guard

Validate before calling

let px = if let OrderAny::TrailingStopLimit(o) = &order {
    o.price
} else {
    Some(order.limit_px())
};

Type guard

fn trailing_limit_price(order: &OrderAny) -> Option<Price> {
    match order {
        OrderAny::TrailingStopLimit(o) => o.price,
        _ => None,
    }
}

Try / catch

// guard the variant; limit_px panics rather than returning Err
if let OrderAny::TrailingStopLimit(o) = &order {
    if let Some(px) = o.price { /* use px */ }
}

Prevention

When it happens

Trigger: Calling OrderAny::limit_px() on an OrderAny::TrailingStopLimit whose price field is None (constructed without an explicit price, or before activation/trigger).

Common situations: Portfolio or reconciliation code enumerating prices for all open orders including trailing stop-limits built with only activation/trailing offsets, assuming a limit price always exists.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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