nautechsystems/nautilus_trader · error

Cannot batch cancel empty order list

Error message

Cannot batch cancel empty order list

What it means

Input guard in Strategy::cancel_orders: the batch cancel was called with an empty client order ID list. A cancel request must reference at least one order, so the empty batch is rejected before any command is sent.

Source

Thrown at crates/trading/src/strategy/mod.rs:684

    }

    /// Batch cancels multiple orders for the same instrument.
    ///
    /// # Errors
    ///
    /// Returns an error if the strategy is not registered, the orders span multiple instruments,
    /// or contain emulated/local orders.
    fn cancel_orders(
        &mut self,
        client_order_ids: Vec<ClientOrderId>,
        client_id: Option<ClientId>,
        params: Option<Params>,
    ) -> anyhow::Result<()>
    where
        Self: StrategyNative,
    {
        if client_order_ids.is_empty() {
            anyhow::bail!("Cannot batch cancel empty order list");
        }

        let (trader_id, strategy_id, ts_init) = {
            let core = StrategyNative::strategy_core_mut(self);
            (
                registered_trader_id(core)?,
                registered_strategy_id(core)?,
                core.clock_mut().timestamp_ns(),
            )
        };

        // TODO: Snapshot all orders from the cache. See `cancel_order` for the rationale.
        let orders: Vec<OrderAny> = {
            let cache_rc = StrategyNative::strategy_core_mut(self).cache_rc();
            let cache = cache_rc.borrow();
            client_order_ids
                .iter()
                .map(|id| {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure the ID list is non-empty before calling cancel_orders
  2. Skip the call when empty: if ids.is_empty() { return; }
  3. Use cancel_all_orders if the intent is to cancel everything regardless of count

Example fix

// before
strategy.cancel_orders(&ids, instrument_id, None, None).await?;
// after
if !ids.is_empty() {
    strategy.cancel_orders(&ids, instrument_id, None, None).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

if client_order_ids.is_empty() {
    return Ok(()); // or use cancel_all_orders instead
}

Type guard

fn is_non_empty<T>(items: &[T]) -> bool { !items.is_empty() }

Prevention

When it happens

Trigger: Calling `strategy.cancel_orders(vec![], instrument_id, None, None)` or passing an empty filtered list of client order IDs.

Common situations: Filtering IDs of already-closed orders down to zero; cancel-all implementations that pass a list collected from a cache that happens to be empty; default/uninitialized vectors.

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