nautechsystems/nautilus_trader · error
Order in list denied: duplicate {}
Error message
Order in list denied: duplicate {} What it means
While registering the list's orders, submit_order_list checks each client_order_id against the cache; if an order with that ID already exists it bails with 'Order in list denied: duplicate {id}'. Client order IDs must be unique within the cache.
Source
Thrown at crates/trading/src/strategy/mod.rs:277
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 {
publish_order_initialized(order);
}
let params = params.filter(|params| !params.is_empty());
View on GitHub (pinned to 18893faf8b)
Solutions
- Rely on the order factory to generate unique client order IDs; avoid hand-assigning them.
- Check cache.order_exists(client_order_id) before submitting each order.
- On restart/replay, seed the factory so IDs continue after the last used value rather than restarting.
Example fix
// before
order = self.order_factory.limit(..., client_order_id=ClientId("fixed-1"))
// after
if not self.cache.order_exists(client_order_id):
order = self.order_factory.limit(...) # factory-generated unique ID Defensive patterns
Strategy: validation
Validate before calling
dupes = [o.client_order_id for o in orders if self.cache.order_exists(o.client_order_id)]
if dupes:
raise ValueError(f"client order IDs already in cache: {dupes}") Type guard
def all_new_orders(cache, orders) -> bool:
return not any(cache.order_exists(o.client_order_id) for o in orders) Try / catch
try:
self.submit_order_list(order_list)
except RuntimeError as e:
if "Order in list denied: duplicate" in str(e):
self.log.error(f"client order ID collision: {e}")
else:
raise Prevention
- Let the order factory generate client order IDs; avoid hand-assigned fixed IDs
- Persist/seed factory state across restarts so IDs never repeat
- Check cache.order_exists per order before resubmitting after an error
When it happens
Trigger: Any order in the list has a client_order_id already present in the cache — resubmitting submitted orders, or hand-built orders with fixed/colliding client order IDs.
Common situations: Custom client order ID generation that collides across restarts; replaying a session with persisted orders; reusing order factory state so IDs repeat.
Related errors
- OrderList denied: duplicate {}
- DataActor {} must be registered before calling `cache()` - t
- Order {client_order_id} not found
- Position {position_id} not found
- Order for {} not found to determine position ID
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/cb74841a5fb15da6.
Report an issue: GitHub.