nautechsystems/nautilus_trader · error

OrderList::from_orders requires first order to have order_li

Error message

OrderList::from_orders requires first order to have order_list_id

What it means

OrderList::from_orders requires every order in the slice to carry an order_list_id, and reads it from the first order via an expect(). It panics when the first OrderAny was created without an order list id (typically standalone, non-list orders).

Source

Thrown at crates/model/src/orders/list.rs:128

    /// and `strategy_id`. [`OrderList::validate`] checks the syntactic
    /// invariants (non-empty, unique `client_order_ids`); it does not
    /// check cross-field consistency.
    ///
    /// # Panics
    ///
    /// Panics if `orders` is empty, if the first order has no
    /// `order_list_id`, or if orders span more than one venue. Callers
    /// are expected to guard non-empty input; `Strategy::submit_order_list`
    /// filters out the empty case and bails on mixed venues before
    /// reaching this constructor.
    #[must_use]
    pub fn from_orders(orders: &[OrderAny], ts_init: UnixNanos) -> Self {
        let first = orders
            .first()
            .expect("OrderList::from_orders requires non-empty orders");
        let order_list_id = first
            .order_list_id()
            .expect("OrderList::from_orders requires first order to have order_list_id");
        let instrument_id = first.instrument_id();
        let strategy_id = first.strategy_id();
        let venue = instrument_id.venue;

        for order in orders {
            assert!(
                order.instrument_id().venue == venue,
                "OrderList::from_orders requires all orders to share the same venue; \
                 expected {venue}, found {} on {}",
                order.instrument_id().venue,
                order.client_order_id(),
            );
        }

        let client_order_ids = orders.iter().map(Order::client_order_id).collect();

        Self {
            id: order_list_id,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Assign an OrderListId to every order before grouping, e.g. builder.order_list_id(order_list_id) with a shared OrderListId::new(...)
  2. Filter the batch to only orders where order.order_list_id().is_some()
  3. Group orders by their existing order_list_id and build one OrderList per id instead of mixing

Example fix

// before
let list = OrderList::from_orders(&orders, ts_init);
// after
let list_id = OrderListId::new("OL-001");
let orders: Vec<OrderAny> = orders
    .into_iter()
    .map(|o| o.with_order_list_id(list_id.clone())) // ensure id set at build time
    .collect();
let list = OrderList::from_orders(&orders, ts_init);
Defensive patterns

Strategy: validation

Validate before calling

// Rust
if orders.first().and_then(|o| o.order_list_id()).is_none() {
    // assign or reject before grouping
}

Type guard

fn all_have_list_id(orders: &[OrderAny]) -> bool { orders.iter().all(|o| o.order_list_id().is_some()) }

Prevention

When it happens

Trigger: Calling OrderList::from_orders on orders built individually (no OrderListId assigned via OrderListId::new / builder.order_list_id) — the first order's order_list_id() returns None.

Common situations: Mixing hand-built single orders into a batch that is later grouped into an OrderList; constructing orders via APIs that skip list-id assignment (contingent/standalone orders); migrating old persisted orders that predate list ids.

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