{"record":{"id":"f5e32c7ff1b10969","repo":"nautechsystems/nautilus_trader","slug":"cannot-roll-back-external-order-claims-e","errorCode":null,"errorMessage":"Cannot roll back external order claims: {e}","messagePattern":"Cannot roll back external order claims: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/live/src/node/mod.rs","lineNumber":2819,"sourceCode":"        self.kernel\n            .cache\n            .try_borrow_mut()\n            .map_err(|e| anyhow::anyhow!(\"Cannot deregister external order claims: {e}\"))?\n            .set_external_order_claims(strategy_id, &[])?;\n\n        Ok(())\n    }\n\n    pub(crate) fn rollback_external_order_claims(\n        &self,\n        strategy_id: StrategyId,\n        instrument_ids: &[InstrumentId],\n    ) -> anyhow::Result<()> {\n        let mut cache = self\n            .kernel\n            .cache\n            .try_borrow_mut()\n            .map_err(|e| anyhow::anyhow!(\"Cannot roll back external order claims: {e}\"))?;\n        let retained: Vec<_> = cache\n            .external_order_claim_instrument_ids(Some(strategy_id))\n            .into_iter()\n            .filter(|instrument_id| !instrument_ids.contains(instrument_id))\n            .collect();\n        cache.set_external_order_claims(strategy_id, &retained)\n    }\n\n    /// Adds an execution algorithm to the trader.\n    ///\n    /// Execution algorithms are registered in both the component registry (for lifecycle\n    /// management) and the actor registry (for data callbacks via msgbus).\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if:\n    /// - The node is currently running.\n    /// - An execution algorithm with the same ID is already registered.","sourceCodeStart":2801,"sourceCodeEnd":2837,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/live/src/node/mod.rs#L2801-L2837","documentation":"This error wraps a `RefCell::try_borrow_mut` failure on the kernel cache during `rollback_external_order_claims`, which reads the strategy's current claims, filters out the given instrument IDs, and rewrites the retained set. If the cache RefCell is already borrowed on the same thread, the borrow fails and this message is raised. It is called by `add_strategy` during rollback of a failed registration.","triggerScenarios":"A failed `add_strategy` triggers rollback while the cache RefCell is still held by another borrow on the same thread — typically because the failure path runs inside code that itself borrowed the cache, or user code holds a cache borrow while adding strategies.","commonSituations":"Nested strategy registration failures during node startup; rolling back claims from a callback where the cache borrow is alive; concurrent (same-thread) node operations interleaved with strategy registration.","solutions":["Ensure no outstanding cache borrow exists when `add_strategy` (and thus its rollback) runs.","Register strategies at setup time, before the node's event loop holds cache borrows.","If this appears during rollback, look one level up: the original failure plus a live cache borrow; fix the outer borrow scope.","Inspect the wrapped `e` for the conflicting borrow site."],"exampleFix":"// before\nlet cache = node.kernel.cache.borrow();\nnode.add_strategy(strategy, ...)?; // rollback path needs cache mutably\n// after\ndrop(node.kernel.cache.borrow());\nnode.add_strategy(strategy, ...)?;","handlingStrategy":"try-catch","validationCode":"if node.kernel.cache.try_borrow_mut().is_err() {\n    return Err(anyhow::anyhow!(\"cache already mutably borrowed; rollback will fail\"));\n}","typeGuard":null,"tryCatchPattern":"match node.add_strategy(strategy, ids) {\n    Err(e) if e.to_string().contains(\"Cannot roll back external order claims\") => {\n        // fix outer cache borrow scope, then verify claims state via external_order_claim_instrument_ids\n    }\n    other => other?,\n}","preventionTips":["Don't hold a cache borrow while calling add_strategy (its failure path needs the cache mutably)","Fix the primary registration error first; a rollback borrow conflict usually indicates a nested borrow in the failure path","Run strategy registration from a single-threaded setup phase","Log claim state after rollback to confirm consistency"],"tags":["rust","refcell","borrow-conflict","rollback"],"backgroundTag":"refcell-already-borrowed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}