nautechsystems/nautilus_trader · error

Cannot create command BatchModifyOrders: quantity, price, an

Error message

Cannot create command BatchModifyOrders: quantity, price, and trigger were either None or the same as existing values for {}

What it means

For at least one order in the batch, every supplied update (quantity, price, trigger_price) was either None or already equal to the current value, so the command would be a no-op. The library refuses to emit a BatchModifyOrders command that changes nothing.

Source

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

                    updating = true;
                }
            }

            if let Some(trigger_price) = trigger_price {
                if !STOP_ORDER_TYPES.contains(&order.order_type()) {
                    anyhow::bail!(
                        "{} orders do not have a STOP trigger price",
                        order.order_type()
                    );
                }

                if Some(*trigger_price) != order.trigger_price() {
                    updating = true;
                }
            }

            if !updating {
                anyhow::bail!(
                    "Cannot create command BatchModifyOrders: quantity, price, and trigger were \
                    either None or the same as existing values for {}",
                    order.client_order_id()
                );
            }

            if order.is_closed() || order.is_pending_cancel() {
                anyhow::bail!(
                    "Cannot create command BatchModifyOrders: state is {:?}, {order:?}",
                    order.status()
                );
            }
        }

        let params = params.filter(|params| !params.is_empty());
        let mut modifies = Vec::with_capacity(orders.len());

        for (order, (_, quantity, price, trigger_price)) in orders.into_iter().zip(updates) {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check that at least one of quantity/price/trigger_price differs from the order's current value before calling
  2. Skip orders with no effective change: if !updating { continue; } logic at the call site
  3. Refresh order state from the cache so comparisons use current values

Example fix

// before
strategy.modify_orders(&orders, &updates, None, None).await?;
// after
let effective: Vec<_> = orders.iter().zip(updates.iter())
    .filter(|(o, (_, q, p, t))|
        q.is_some_and(|q| *q != o.quantity())
        || p.is_some_and(|p| Some(*p) != o.price())
        || t.is_some_and(|t| Some(*t) != o.trigger_price()))
    .collect();
if !effective.is_empty() {
    strategy.modify_orders(&orders, &updates, None, None).await?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn has_effective_change(o: &OrderAny, q: Option<Quantity>, p: Option<Price>, t: Option<Price>) -> bool {
    q.is_some_and(|q| q != o.quantity())
        || p.is_some_and(|p| Some(p) != o.price())
        || t.is_some_and(|t| Some(t) != o.trigger_price())
}

Prevention

When it happens

Trigger: Calling modify_orders where all Some values match current order state, or all fields are None (e.g. re-running an already-applied modify, or idempotent retry after the first modify succeeded).

Common situations: Idempotent retries after a timeout where the first modify already landed; computing new values from stale cached data; update struct defaults leaving all fields None.

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


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