nautechsystems/nautilus_trader · error · anyhow::Error

Cannot modify order: {e}

Error message

Cannot modify order: {e}

What it means

`modify_order` snapshots the order from the Cache using `try_order_owned(&client_order_id)`; any cache lookup failure (order not found, or a cache borrow/consistency error) is wrapped as `Cannot modify order: {e}` and propagates up (reached via dispatch_manager_actions in Python strategies).

Source

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

        client_id: Option<ClientId>,
        params: Option<Params>,
    ) -> anyhow::Result<()>
    where
        Self: StrategyNative,
    {
        let (trader_id, strategy_id) = {
            let core = StrategyNative::strategy_core_mut(self);
            (registered_trader_id(core)?, registered_strategy_id(core)?)
        };

        let params = params.filter(|params| !params.is_empty());

        // TODO: Snapshot the order from the cache. See `cancel_order` for the rationale.
        let order = StrategyNative::strategy_core_mut(self)
            .cache_rc()
            .borrow()
            .try_order_owned(&client_order_id)
            .map_err(|e| anyhow::anyhow!("Cannot modify order: {e}"))?;

        let mut updating = false;

        if quantity.is_some_and(|q| q != order.quantity() || order.is_pending_update()) {
            updating = true;
        }

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

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

        if let Some(trigger_price) = trigger_price {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the order is still open before modifying: `self.cache.order_exists(client_order_id)` and check its status.
  2. Use the exact StrategyClientOrderId returned by the OrderFactory when the order was submitted.
  3. Move modify calls to `on_order_accepted`/event-driven points where the order is guaranteed open; cancel-and-replace if it may already be terminal.
  4. Read the inner `{e}` to distinguish not-found from borrow errors and handle each accordingly.

Example fix

// before
def on_bar(self, bar):
    self.modify_order(self._order_id, quantity=self._new_qty)  # may already be filled
// after
def on_bar(self, bar):
    if self.cache.order_exists(self._order_id):
        order = self.cache.order(self._order_id)
        if order.is_open:
            self.modify_order(self._order_id, quantity=self._new_qty)
Defensive patterns

Strategy: validation

Validate before calling

if not self.cache.order_exists(client_order_id):
    self.log.warning(f'{client_order_id} not in cache — cannot modify')
    return
order = self.cache.order(client_order_id)
if not order.is_open:
    self.log.warning(f'{client_order_id} is {order.status} — cannot modify')
    return

Type guard

def is_modifiable(strategy, client_order_id):
    order = strategy.cache.order(client_order_id) if strategy.cache.order_exists(client_order_id) else None
    return order is not None and order.is_open

Try / catch

try:
    self.modify_order(client_order_id, quantity=new_qty)
except Exception as e:
    self.log.warning(f'Modify failed for {client_order_id}: {e}')
    # fall back to cancel-and-replace if still open

Prevention

When it happens

Trigger: Calling `self.modify_order(client_order_id, ...)` with a client_order_id that is not in the cache (order already filled/canceled/never submitted), or a malformed ID; the inner `{e}` carries the specific cache error.

Common situations: Modifying an order after it was filled or canceled; racing an execution event that removed the order; wrong client_order_id (using venue order id instead); modifying in `on_order_filled`/`on_order_canceled` after the order left the open set; typo in strategy state mapping IDs to orders.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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