nautechsystems/nautilus_trader · error · anyhow::Error

Cannot cancel order: {e}

Error message

Cannot cancel order: {e}

What it means

Raised in `cancel_order` when the cache cannot return an owned snapshot of the order for the given client_order_id, so a CancelOrder command cannot be built. The strategy snapshots the order (releasing the cache borrow before later re-entrant calls) and fails fast if the lookup errors.

Source

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

        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 params = params.filter(|params| !params.is_empty());

        // TODO: Snapshot the order from the cache. Callers identify it by ID; we own the
        // snapshot so later calls (which take `&OrderAny` and may re-enter the cache)
        // run without holding a live cache borrow.
        let order = StrategyNative::strategy_core_mut(self)
            .cache_rc()
            .borrow()
            .try_order_owned(&client_order_id)
            .map_err(|e| anyhow::anyhow!("Cannot cancel order: {e}"))?;

        if !self.mark_order_pending_cancel(&order)? {
            return Ok(());
        }

        let command = CancelOrder::new(
            trader_id,
            client_id,
            strategy_id,
            order.instrument_id(),
            order.client_order_id(),
            order.venue_order_id(),
            UUID4::new(),
            ts_init,
            params,
            None, // correlation_id
        );

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check cache.order(&client_order_id) is Some before cancelling.
  2. Ensure cancel_all_orders / timers only run for orders still open in the cache.
  3. Confirm the strategy owns the orders (correct client_id on submission).
  4. Handle the error gracefully on reconnection where order state may not yet be reconciled.

Example fix

// before
strategy.cancel_order(&stale_id)?;
// after
if let Some(order) = cache.order(&stale_id) {
    if order.is_open() { strategy.cancel_order(&stale_id)?; }
}
Defensive patterns

Strategy: validation

Validate before calling

if cache.order(&client_order_id).is_none() { log::warn!("cannot cancel unknown order {client_order_id}"); return; }

Try / catch

if let Err(e) = strategy.cancel_order(&id) {
    log::warn!("cancel failed for {id}: {e}"); // skip instead of aborting cancel_all
}

Prevention

When it happens

Trigger: Calling `cancel_order` (directly or via cancel_all_orders, dispatch_manager_actions, set_gtd_expiry, expire_gtd_order, reactivate_gtd_timers) with a client_order_id absent from the cache or not retrievable via `try_order_owned`.

Common situations: Cancelling an order already filled/expired and dropped from the live index, cancelling externally submitted orders not tracked by this strategy, or timer-based expiry firing for a stale order.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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