nautechsystems/nautilus_trader · error
OrderList denied: orders must share the same venue; expected
Error message
OrderList denied: orders must share the same venue; expected {first_venue}, found {} on {} What it means
All orders in one OrderList must target the same venue. submit_order_list takes the venue of the first order and bails if any subsequent order's instrument_id.venue differs, because a list is processed as a single atomic submission to one execution venue.
Source
Thrown at crates/trading/src/strategy/mod.rs:221
{
if orders.is_empty() {
log::error!("OrderList denied: no orders to submit");
anyhow::bail!("OrderList denied: no orders to submit");
}
for order in &orders {
if order.status() != OrderStatus::Initialized {
anyhow::bail!(
"Order in list denied: invalid status for {}, expected INITIALIZED",
order.client_order_id()
);
}
}
let first_venue = orders[0].instrument_id().venue;
for order in &orders {
if order.instrument_id().venue != first_venue {
anyhow::bail!(
"OrderList denied: orders must share the same venue; \
expected {first_venue}, found {} on {}",
order.instrument_id().venue,
order.client_order_id(),
);
}
}
let should_deny = {
let core = StrategyNative::strategy_core_mut(self);
let tag = core.market_exit_tag;
core.is_exiting
&& orders.iter().any(|o| {
!o.is_reduce_only() && !o.tags().is_some_and(|tags| tags.contains(&tag))
})
};
if should_deny {View on GitHub (pinned to 18893faf8b)
Solutions
- Partition orders by instrument_id.venue and submit one OrderList per venue.
- Group orders by instrument before batching so a list never spans venues.
- Assert all orders share the first order's venue before calling submit_order_list.
Example fix
// before
self.submit_order_list(OrderList(all_orders))
// after
from itertools import groupby
for venue, group in groupby(sorted(all_orders, key=lambda o: o.instrument_id.venue), key=lambda o: o.instrument_id.venue):
self.submit_order_list(OrderList(list(group))) Defensive patterns
Strategy: validation
Validate before calling
venues = {o.instrument_id.venue for o in orders}
if len(venues) > 1:
raise ValueError(f"order list spans venues: {venues}; submit one list per venue") Type guard
def single_venue(orders) -> bool:
return len({o.instrument_id.venue for o in orders}) <= 1 Try / catch
try:
self.submit_order_list(order_list)
except RuntimeError as e:
if "must share the same venue" in str(e):
self.log.error("split batch by venue and resubmit")
else:
raise Prevention
- Group orders by instrument_id.venue before batching submissions
- Never aggregate orders across instruments on different venues into one list
- Add an assert/single-venue check in any batch-submission helper
When it happens
Trigger: Passing orders for instruments on two or more venues (e.g. BINANCE and BYBIT, or an equities venue and a futures venue) in a single submit_order_list call.
Common situations: Multi-venue strategies batching orders from an aggregation loop; a grouping bug where orders are collected across instruments without partitioning by venue.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- OrderList denied: no orders to submit
- OrderList denied: {e}
- Invalid order side: {e}
- missing limit price for order {} (market orders require an e
- limit_price is required for order type {order_type:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b524cc18272a7f19.
Report an issue: GitHub.