nautechsystems/nautilus_trader · error

OrderFactory::create_list requires non-empty orders

Error message

OrderFactory::create_list requires non-empty orders

What it means

OrderFactory::create_list builds an OrderList from a slice of orders and derives the shared instrument_id/venue from the first order. It panics when the slice is empty; the public wrapper filters out empty input and mixed venues before reaching this constructor, so hitting it means the guard was bypassed.

Source

Thrown at crates/common/src/factories/order.rs:1092

    /// Creates a new [`OrderList`] from the given orders, generating a fresh
    /// order list ID and propagating it back to each order.
    ///
    /// All orders must share the same venue; the caller is responsible for
    /// passing orders with the factory's `strategy_id`. The returned list's
    /// invariants are checked by [`OrderList::validate`] at submission time.
    ///
    /// # Panics
    ///
    /// Panics if `orders` is empty 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 create_list(&mut self, orders: &mut [OrderAny], ts_init: UnixNanos) -> OrderList {
        let instrument_id = orders
            .first()
            .expect("OrderFactory::create_list requires non-empty orders")
            .instrument_id();
        let venue = instrument_id.venue;

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

        let order_list_id = self.generate_order_list_id();
        let order_ids: Vec<ClientOrderId> = orders.iter().map(OrderAny::client_order_id).collect();

        for order in orders.iter_mut() {
            order.set_order_list_id(order_list_id);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check !orders.is_empty() before calling create_list
  2. Filter upstream so empty lists short-circuit and return an empty/None result instead
  3. If mixing venues is possible, group orders by venue first (create_list also asserts a single venue)
  4. Prefer the public wrapper that documents the empty-case filtering

Example fix

// before
let list = factory.create_list(&mut orders, ts_init);
// after
assert!(!orders.is_empty(), "no orders to submit");
let list = factory.create_list(&mut orders, ts_init);
Defensive patterns

Strategy: validation

Validate before calling

if orders.is_empty() {
    return Ok(OrderList::default()); // or early-return your own error
}
let venue = orders[0].instrument_id().venue;
if orders.iter().any(|o| o.instrument_id().venue != venue) {
    return Err("mixed venues in create_list input".into());
}

Type guard

fn non_empty(orders: &[OrderAny]) -> Option<&[OrderAny]> {
    if orders.is_empty() { None } else { Some(orders) }
}

Try / catch

// Panic is not catchable; guard before the call
assert!(!orders.is_empty(), "create_list requires at least one order");
let list = factory.create_list(&mut orders, ts_init);

Prevention

When it happens

Trigger: Calling create_list with an empty orders slice directly (or via a path that skips the emptiness check), then reading orders.first() -> None -> panic.

Common situations: Building order lists from a dynamically filtered collection that ended up empty (e.g. all orders filtered out); tests constructing lists directly; upstream code passing Vec::new().

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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