nautechsystems/nautilus_trader · error
Cannot deregister external order claims: {e}
Error message
Cannot deregister external order claims: {e} What it means
This error wraps a `RefCell::try_borrow_mut` failure on the kernel cache when `deregister_external_order_claims` attempts to clear a strategy's external order claims (it calls `set_external_order_claims(strategy_id, &[])`). The cache RefCell is already borrowed elsewhere on the same thread, so the mutable borrow fails. It is an aliasing/re-entrancy error, not a claim-related domain error.
Source
Thrown at crates/live/src/node/mod.rs:2804
}
Ok(())
}
/// Deregisters all external order claims owned by `strategy_id` from the shared cache.
///
/// The operation is synchronous and can be called while the node is idle, after manual
/// [`start`](Self::start) returns, or after the node stops. It cannot be called while
/// [`run`](Self::run) or [`run_with_mode`](Self::run_with_mode) owns the node.
///
/// # Errors
///
/// Returns an error if the cache is already borrowed.
pub fn deregister_external_order_claims(&self, strategy_id: StrategyId) -> anyhow::Result<()> {
self.kernel
.cache
.try_borrow_mut()
.map_err(|e| anyhow::anyhow!("Cannot deregister external order claims: {e}"))?
.set_external_order_claims(strategy_id, &[])?;
Ok(())
}
pub(crate) fn rollback_external_order_claims(
&self,
strategy_id: StrategyId,
instrument_ids: &[InstrumentId],
) -> anyhow::Result<()> {
let mut cache = self
.kernel
.cache
.try_borrow_mut()
.map_err(|e| anyhow::anyhow!("Cannot roll back external order claims: {e}"))?;
let retained: Vec<_> = cache
.external_order_claim_instrument_ids(Some(strategy_id))
.into_iter()View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the cache borrow is released (drop guards) before deregistering.
- Perform deregistration outside callbacks, e.g. in the outer shutdown path.
- Defer the call via a queue processed where no cache borrow is held.
- Check the wrapped `e` text for the location of the conflicting borrow.
Example fix
// before // inside on_stop while cache may be borrowed node.deregister_external_order_claims(strategy_id)?; // after // schedule teardown outside the callback scope telemetry_queue.push(TearDown::DeregisterClaims(strategy_id));
Defensive patterns
Strategy: try-catch
Validate before calling
if node.kernel.cache.try_borrow().is_err() {
return Err(anyhow::anyhow!("cache already borrowed; defer claim deregistration"));
} Try / catch
match node.deregister_external_order_claims(strategy_id) {
Ok(()) => {},
Err(e) if e.to_string().contains("Cannot deregister external order claims") => {
// schedule teardown where no cache borrow is held
}
Err(e) => return Err(e),
} Prevention
- Deregister claims outside strategy on_stop callbacks while node dispatch holds borrows
- Centralize strategy add/remove in one owner scope
- Keep cache borrow lifetimes short and scoped
- Prefer the node's own teardown/shutdown path for cleanup
When it happens
Trigger: Calling `deregister_external_order_claims` while the kernel cache is borrowed — e.g. from inside an event/data callback holding a cache borrow, or while another node operation (like `add_strategy`) is mid-call on the same thread.
Common situations: Tearing down strategies from within their own `on_stop` handler while the cache borrow from dispatch is alive; interleaving strategy add/remove calls in async tasks sharing the node on one thread.
Related errors
- Cannot register external order claims: {e}
- Cannot register OMS type: {e}
- Cannot roll back external order claims: {e}
- DataActor {} must be registered before calling `cache()` - t
- Order {client_order_id} not found
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/90bb5cf637d04cd9.
Report an issue: GitHub.