nautechsystems/nautilus_trader · error

OrderList denied: duplicate {}

Error message

OrderList denied: duplicate {}

What it means

The cache already contains an OrderList with the same list ID, so submit_order_list bails with 'OrderList denied: duplicate {id}'. Order list IDs must be unique per trading session; the cache rejects a second registration of the same list.

Source

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

            core.order_factory().create_list(&mut orders, ts_init)
        };

        if let Err(e) = order_list.validate() {
            log::error!("OrderList denied: {e}");
            anyhow::bail!("OrderList denied: {e}");
        }

        {
            let cache_rc = core.cache_rc();
            let mut cache = cache_rc.try_borrow_mut().map_err(|_| {
                anyhow::anyhow!(
                    "Cannot submit order list {}: cache is currently borrowed",
                    order_list.id
                )
            })?;

            if cache.order_list_exists(&order_list.id) {
                anyhow::bail!("OrderList denied: duplicate {}", order_list.id);
            }

            for order in &orders {
                if cache.order_exists(&order.client_order_id()) {
                    anyhow::bail!(
                        "Order in list denied: duplicate {}",
                        order.client_order_id()
                    );
                }
            }

            cache.add_order_list(order_list.clone())?;
            for order in &orders {
                cache.add_order(order.clone(), position_id, client_id, true)?;
            }
        }

        for order in &orders {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Create a new OrderList via the order factory so a fresh list ID is generated.
  2. Check cache.order_list_exists(id) (or self.cache on the Python side) before submitting.
  3. On retries after an error, assume the list may already be registered and use new orders/IDs instead of resubmitting.

Example fix

// before
self.submit_order_list(order_list)

// after
if not self.cache.order_list_exists(order_list.id):
    self.submit_order_list(order_list)
Defensive patterns

Strategy: validation

Validate before calling

if self.cache.order_list_exists(order_list.id):
    self.log.warning(f"order list {order_list.id} already registered; skipping")
    return

Type guard

def is_new_order_list(cache, order_list) -> bool:
    return not cache.order_list_exists(order_list.id)

Try / catch

try:
    self.submit_order_list(order_list)
except RuntimeError as e:
    if "duplicate" in str(e):
        self.log.warning(f"order list already in cache: {e}")
    else:
        raise

Prevention

When it happens

Trigger: Submitting an OrderList whose id already exists in the cache — resubmitting the same list object, or replaying a run where deterministic list IDs collide.

Common situations: Retry logic that resubmits the same list after an ambiguous failure; strategy restart/replay reusing factory IDs; constructing an OrderList manually with a fixed id.

Related errors


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