nautechsystems/nautilus_trader · error
Cannot batch modify empty order list
Error message
Cannot batch modify empty order list
What it means
`modify_orders` refuses to build a BatchModifyOrders command when the `updates` list is empty. A batch request must contain at least one (order, update) pair; an empty list would produce a meaningless or invalid command for the execution engine. The bail happens before any trader/strategy IDs are resolved.
Source
Thrown at crates/trading/src/strategy/mod.rs:464
/// Batch modifies multiple orders for the same instrument.
///
/// Each tuple is `(client_order_id, quantity, price, trigger_price)`.
///
/// # Errors
///
/// Returns an error if the strategy is not registered, the orders span multiple instruments,
/// contain emulated/local orders, or a child modify is invalid.
fn modify_orders(
&mut self,
updates: Vec<BatchModifyOrder>,
client_id: Option<ClientId>,
params: Option<Params>,
) -> anyhow::Result<()>
where
Self: StrategyNative,
{
if updates.is_empty() {
anyhow::bail!("Cannot batch modify 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(),
)
};
let orders: Vec<OrderAny> = {
let cache_rc = StrategyNative::strategy_core_mut(self).cache_rc();
let cache = cache_rc.borrow();
updates
.iter()
.map(|(client_order_id, _, _, _)| {
cacheView on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the updates list is non-empty before calling modify_orders
- Guard the call: if updates.is_empty() { return Ok(()); } (skip instead of error)
- Check upstream logic that filters/derives the update list so it cannot drop all entries
- If an empty batch is legitimately a no-op, handle it at the call site rather than invoking the API
Example fix
// before
strategy.modify_orders(updates, instrument_id, None, None).await?;
// after
if !updates.is_empty() {
strategy.modify_orders(updates, instrument_id, None, None).await?;
} Defensive patterns
Strategy: validation
Validate before calling
if updates.is_empty() {
// no-op or return early; do not call modify_orders
return Ok(());
} Type guard
fn is_non_empty<T>(items: &[T]) -> bool { !items.is_empty() } Prevention
- Guard empty batches at the call site
- Be careful with filter chains that can drain the update list to zero
- Log/skip no-op batches instead of invoking the API
When it happens
Trigger: Calling `strategy.modify_orders(vec![], instrument_id, None, None)` (or an updates slice built by filtering an original list down to zero elements).
Common situations: Filtering pending updates before the call (e.g. skipping already-closed orders) so the vec becomes empty; upstream data returning no actionable updates; uninitialized/default vectors passed by mistake.
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
- Cannot batch cancel empty order list
- batch_add requires at least one order
- No symbols provided
- At least one --address or --addresses-file entry is required
- Quote maps must not be empty
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9b16b7ef1a65e460.
Report an issue: GitHub.