nautechsystems/nautilus_trader · error

Limit order must have a price

Error message

Limit order must have a price

What it means

The matching engine's order-filling path matched a LIMIT order whose price is None. A limit order is defined by its price; without one the engine cannot determine the book price level to fill against, so it panics. This invariant failure means a malformed limit order reached the fill logic instead of being rejected earlier.

Source

Thrown at crates/execution/src/matching_engine/mod.rs:4280

                                    self.target_ask = self.core.ask;
                                    self.target_last = self.core.last;
                                    self.core.set_bid_raw(target_price);
                                    self.core.set_last_raw(target_price);
                                    fill.0 = target_price;
                                }
                            }
                        }
                    }
                }

                self.apply_liquidity_consumption(
                    fills,
                    order.order_side(),
                    order.leaves_qty(),
                    book_prices_ref,
                )
            }
            None => panic!("Limit order must have a price"),
        }
    }

    fn determine_market_price_and_volume(&self, order: &OrderAny) -> Vec<(Price, Quantity)> {
        let price = match order.order_side() {
            OrderSide::Buy => Price::max(FIXED_PRECISION),
            OrderSide::Sell => Price::min(FIXED_PRECISION),
        };

        // When liquidity consumption is enabled, get ALL crossed levels so that
        // consumed levels can be filtered out while still finding valid ones.
        let mut fills = if self.config.liquidity_consumption {
            let size_prec = self.instrument.size_precision();
            self.book
                .get_all_crossed_levels(order.order_side(), price, size_prec)
        } else {
            let book_order = BookOrder::new(order.order_side(), price, order.quantity(), 0);
            self.book.simulate_fills(&book_order)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Always set a valid Price when creating a LIMIT order (use instrument.make_price(...) to get correct precision).
  2. Add a pre-submission check that limit orders carry a price so they are rejected at the strategy/client layer instead of panicking in the engine.
  3. Check serialization/deserialization of orders (e.g. redis-backed caches) so the price field is not dropped.
  4. Verify order_type classification in adapter conversions between venue and Nautilus order types.

Example fix

// before
OrderFactory::limit(instrument_id, OrderSide::Buy, qty) // price omitted
// after
let price = instrument.make_price(100.25);
OrderFactory::limit(instrument_id, OrderSide::Buy, qty, Price(price))
Defensive patterns

Strategy: validation

Validate before calling

if order.order_type() == OrderType::Limit && order.price().is_none() {
    return Err(anyhow!("limit order {} missing price", order.client_order_id()));
}

Type guard

fn limit_has_price(order: &OrderAny) -> bool {
    order.order_type() != OrderType::Limit || order.price().is_some()
}

Prevention

When it happens

Trigger: Calling the limit fill routine (determine_price_and_volume-style path around matching_engine/mod.rs:4280) with an OrderAny of type Limit whose price() returns None (match arm `None => panic!(...)`).

Common situations: Constructing a Limit order without setting price (or with price lost during deserialization/conversion); adapter code misclassifying a market order as limit; corrupt order state after cache round-trip.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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