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
- Verify the order is still open before modifying: `self.cache.order_exists(client_order_id)` and check its status.
- Use the exact StrategyClientOrderId returned by the OrderFactory when the order was submitted.
- 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.
- 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
- Confirm the order exists and is open before modify calls
- Store and reuse the client_order_id returned by the OrderFactory
- Avoid modifying from terminal-event callbacks (on_order_filled/canceled)
- Prefer cancel-and-replace when the order state may have changed
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
- External order claim for {instrument_id} appears more than o
- External order claim for {instrument_id} already exists for
- load_strategy not implemented for PostgreSQL cache adapter:
- OrderList denied: duplicate {}
- Order in list denied: duplicate {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/400c518e08dfb010.
Report an issue: GitHub.