nautechsystems/nautilus_trader · error · anyhow::Error
Cannot submit order {order.client_order_id()}: cache is curr
Error message
Cannot submit order {order.client_order_id()}: cache is currently borrowed What it means
Raised in `submit_order_native` when the strategy cache is already mutably (or immutably) borrowed at the point the binding tries `try_borrow_mut`, so the new order cannot be added to the cache. This is a runtime borrow-check guard of the RefCell-based cache, not a domain error.
Source
Thrown at crates/trading/src/strategy/mod.rs:2359
let market_exit_tag = core.market_exit_tag;
let is_market_exit_order = order
.tags()
.is_some_and(|tags| tags.contains(&market_exit_tag));
let should_deny_for_market_exit =
core.is_exiting && !order.is_reduce_only() && !is_market_exit_order;
if should_deny_for_market_exit {
strategy.deny_order(order, Ustr::from("MARKET_EXIT_IN_PROGRESS"));
return Ok(());
}
let core = StrategyNative::strategy_core_mut(strategy);
let params = params.filter(|params| !params.is_empty());
{
let cache_rc = core.cache_rc();
let mut cache = cache_rc.try_borrow_mut().map_err(|_| {
anyhow::anyhow!(
"Cannot submit order {}: cache is currently borrowed",
order.client_order_id()
)
})?;
cache.add_order(order.clone(), position_id, client_id, true)?;
}
publish_order_initialized(order);
let command = SubmitOrder::new(
trader_id,
client_id,
strategy_id,
order.instrument_id(),
order.client_order_id(),
order.init_event().clone(),
order.exec_algorithm_id(),
position_id,View on GitHub (pinned to 18893faf8b)
Solutions
- Do not submit orders from inside callbacks that hold a cache borrow; defer via a message queue or flag.
- Scope cache borrows tightly (drop them before calling back into strategy methods).
- Avoid holding the result of cache.borrow()/borrow_mut() across calls into strategy APIs.
- Restructure so submission happens after event handling completes (e.g. in the next timer tick).
Example fix
// before
fn on_order(&mut self, event: &OrderEventAny) {
self.submit_order(new_order)?; // cache still borrowed here
}
// after
fn on_order(&mut self, event: &OrderEventAny) {
self.pending_submits.push(new_order); // submit after borrow released
} Defensive patterns
Strategy: try-catch
Validate before calling
// No pre-call check exists; ensure no live cache borrow on the calling path // (avoid calling submit_order inside on_event/on_order callbacks that borrow cache)
Try / catch
if let Err(e) = strategy.submit_order(&order) {
if e.to_string().contains("cache is currently borrowed") {
deferred_submits.push(order); // retry after handler returns
}
} Prevention
- Never submit orders from inside callbacks holding a cache borrow
- Scope cache.borrow()/borrow_mut() tightly and drop before re-entering strategy APIs
- Queue submissions and flush them after event handling completes
When it happens
Trigger: Calling `submit_order` from a callback/re-entrant path (e.g. inside an event handler or from `binding_submit_order`) while another piece of code still holds a borrow of the strategy cache on the same thread.
Common situations: Submitting an order directly from within on_order/on_event/order-book callbacks that hold a cache borrow, or nested strategy calls where an earlier `cache.borrow()` was not released.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Cannot register OMS type: {e}
- Cannot register external order claims: {e}
- Cannot deregister external order claims: {e}
- Cannot roll back external order claims: {e}
- Invalid config type for AxExecutionClientFactory. Expected A
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d31c91368cf2f975.
Report an issue: GitHub.