nautechsystems/nautilus_trader · error · anyhow::Error
Cannot set external order claims: {e}
Error message
Cannot set external order claims: {e} What it means
While setting external order instrument IDs, the strategy borrows the shared Cache mutably via `cache.try_borrow_mut()`. If the Cache RefCell is already borrowed (by this or another actor on the same thread) the borrow fails and the error is re-wrapped as `Cannot set external order claims: {e}`.
Source
Thrown at crates/trading/src/strategy/mod.rs:140
///
/// Returns an error if the strategy is not registered, the cache is already borrowed, an
/// instrument is repeated, or an instrument is claimed by another strategy.
fn set_external_order_instrument_ids(
&mut self,
instrument_ids: Vec<InstrumentId>,
) -> anyhow::Result<()>
where
Self: StrategyNative,
{
let core = StrategyNative::strategy_core_mut(self);
let strategy_id = registered_strategy_id(core)?;
if !core.actor.is_registered() {
anyhow::bail!("Strategy {strategy_id} is not registered with a trader");
}
let cache = core.cache_rc();
cache
.try_borrow_mut()
.map_err(|e| anyhow::anyhow!("Cannot set external order claims: {e}"))?
.set_external_order_claims(strategy_id, &instrument_ids)?;
core.config.external_order_instrument_ids = Some(instrument_ids);
Ok(())
}
/// Returns the runtime strategy ID, when configured or registered.
fn strategy_id(&self) -> Option<StrategyId>
where
Self: StrategyNative,
{
StrategyNative::strategy_core(self).strategy_id()
}
/// Returns the user-facing order creation API.
fn order(&self) -> OrderApi<'_>
where
Self: StrategyNative,
{View on GitHub (pinned to 18893faf8b)
Solutions
- Call `set_external_order_instrument_ids` from `on_start` or another point where no cache borrow is held.
- Do not retain cache borrow guards across calls; drop any `cache` handle obtained earlier before invoking.
- Restructure so the claims are set outside any cache iteration/dispatch context.
- If `{e}` indicates a persistent borrow, look for leaked borrows in custom actor code on the same thread.
Example fix
// before
def on_start(self):
orders = self.cache.orders_open() # holds an internal borrow
self.set_external_order_instrument_ids([...]) # fails: cache already borrowed
// after
def on_start(self):
self.set_external_order_instrument_ids([...])
orders = self.cache.orders_open() Defensive patterns
Strategy: validation
Try / catch
try:
self.set_external_order_instrument_ids(ids)
except Exception as e:
if 'currently borrowed' in str(e):
self.clock.set_timer('retry-claims', 0.001, callback=self._retry_claims)
else:
raise Prevention
- Never hold cache handles or iteration state across claims setup
- Call claims setup from on_start when no dispatch is in flight
- Avoid nested calls into the cache within the same callback stack
- Treat cache borrow errors as re-entrancy bugs in your own code
When it happens
Trigger: Calling `set_external_order_instrument_ids` while the Cache is mutably borrowed — e.g. from within a callback that itself holds a cache borrow, or nested cache access during dispatch on the same thread.
Common situations: Holding a cache reference (e.g. from `cache.orders()` iteration or a previous try_borrow_mut result) across the call; calling claims setup from inside `on_event`/handler code while the engine is mid-dispatch; deep call chains where an outer function still holds the borrow.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Cannot submit order list {order_list.id}: cache is currently
- load_strategy not implemented for PostgreSQL cache adapter:
- OrderList denied: duplicate {}
- Order in list denied: duplicate {}
- Cannot clear external order claims: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/441646b17870c2b1.
Report an issue: GitHub.