{"record":{"id":"f8e7d3977e152fd0","repo":"nautechsystems/nautilus_trader","slug":"cannot-update-position-not-found-in-cache","errorCode":null,"errorMessage":"Cannot update position {}: not found in cache","messagePattern":"Cannot update position (.+?): not found in cache","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/cache/mod.rs","lineNumber":5433,"sourceCode":"    /// Updates the `order` as pending cancel locally.\n    pub fn update_order_pending_cancel_local(&mut self, order: &OrderAny) {\n        self.index\n            .orders_pending_cancel\n            .insert(order.client_order_id());\n    }\n\n    /// Updates a `position` already held in the cache.\n    ///\n    /// Reuses the existing cell so any held [`PositionRef`] handles continue to point at the\n    /// canonical entry.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the position is not already held in the cache, or if updating the\n    /// position in the database fails.\n    pub fn update_position(&mut self, position: &Position) -> anyhow::Result<()> {\n        let Some(position_cell) = self.positions.get(&position.id).cloned() else {\n            anyhow::bail!(\"Cannot update position {}: not found in cache\", position.id);\n        };\n\n        self.refresh_position_indexes(position);\n\n        *position_cell.borrow_mut() = position.clone();\n\n        if let Some(database) = &mut self.database {\n            database.update_position(position)?;\n            // TODO: Implement order snapshots\n            // if self.snapshot_orders {\n            //     database.snapshot_order_state(order)?;\n            // }\n        }\n\n        Ok(())\n    }\n\n    /// Updates a cached position by applying an order fill in place.","sourceCodeStart":5415,"sourceCodeEnd":5451,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/cache/mod.rs#L5415-L5451","documentation":"`update_position` requires the position to already exist in the cache; it mutates the existing shared cell in place. If no position with that ID is held, the method bails instead of creating one — updates are strictly for existing positions (new positions are added via `add_position`).","triggerScenarios":"Calling `update_position(&position)` for a PositionId never added to the cache, or one already removed/purged (e.g. after `purge_...` of closed positions); passing a position built locally rather than one returned by the cache.","commonSituations":"Replaying events after the cache was purged of closed positions; restoring state from a snapshot incompletely; constructing a Position in code and trying to 'update' it before any add.","solutions":["Call `add_position` for new positions before any `update_position` call.","Guard the update with `cache.position(&position.id)` / existence check and add if absent.","Re-order purge logic so positions are not purged while updates for them are still expected."],"exampleFix":"// before\ncache.update_position(&position)?;\n// after\nif cache.position(&position.id).is_some() {\n    cache.update_position(&position)?;\n} else {\n    cache.add_position(position.clone());\n}","handlingStrategy":"validation","validationCode":"if cache.position(&position.id).is_none() {\n    cache.add_position(position.clone()); // or skip update\n} else {\n    cache.update_position(&position)?;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check existence before updating positions.","Sequence purges after all pending updates for a position are done.","Distinguish add vs update in event-handling code paths."],"tags":["rust","cache","position","not-found"],"backgroundTag":"entity-not-found","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"}