nautechsystems/nautilus_trader · error
Account {account_id} not found after cache update
Error message
Account {account_id} not found after cache update What it means
`update_account_owned` writes the account into the in-memory cache, then needs it (as a shared cell) to persist to the backing database. If the account cannot be found in `self.accounts` immediately after `cache_account_owned`, an internal invariant was violated (the cache-upsert failed to store it), so the update aborts before touching the database.
Source
Thrown at crates/common/src/cache/mod.rs:5232
Some(account_cell) => *account_cell.borrow_mut() = account,
None => {
self.accounts.insert(account_id, SharedCell::new(account));
}
}
}
/// Updates the `account` in the cache, taking ownership of the updated account.
///
/// # Errors
///
/// Returns an error if updating the account in the database fails.
pub fn update_account_owned(&mut self, account: AccountAny) -> anyhow::Result<()> {
let account_id = account.id();
self.cache_account_owned(account);
if let Some(database) = &mut self.database {
let Some(account_cell) = self.accounts.get(&account_id) else {
anyhow::bail!("Account {account_id} not found after cache update");
};
database.update_account(&account_cell.borrow())?;
}
Ok(())
}
/// Applies an account state event to the cached account.
///
/// Mutates the cached account in place to avoid cloning the account event
/// history on the hot path; long-running sessions accumulate many events
/// per account, so a snapshot-clone here would be O(history) per update.
///
/// # Errors
///
/// Returns an error if applying or persisting the account state fails.
pub fn update_account_state(&mut self, event: &AccountState) -> anyhow::Result<()> {
let Some(cell) = self.accounts.get(&event.account_id) else {
return self.add_account(AccountAny::from_events(std::slice::from_ref(event))?);View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the account is added via the supported `add_account`/`update_account` path so `cache_account_owned` succeeds.
- Verify the account's AccountId is stable and unique; do not mutate it after construction.
- Rebuild/reload the cache if its internal state was cleared concurrently; check for multi-owner access to the cache.
Defensive patterns
Strategy: try-catch
Validate before calling
if cache.account(&account_id).is_none() {
// add the account via the supported path before update_account_owned
} Try / catch
if let Err(e) = cache.update_account_owned(account) {
// treat as internal invariant violation: log state, consider cache reload
} Prevention
- Add accounts only through the supported cache APIs.
- Never mutate an AccountId after construction.
- Avoid sharing one Cache across owners that can clear state concurrently.
When it happens
Trigger: Calling `update_account_owned` when `cache_account_owned` failed to insert the account (e.g. an account with a colliding or malformed AccountId, or corrupted cache state); a database-backed cache whose account map was cleared concurrently by another owner.
Common situations: Persistent (backed) caches where an account was removed between the write and the read; custom account types whose `id()` collides or changes; bespoke code paths inserting accounts without going through the cache.
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 persist account with no events: {}
- Cannot persist position with no events: {}
- DataActor {} must be registered before calling `cache()` - t
- Order {client_order_id} not found
- Position {position_id} not found
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/a19d15a327f7c2b8.
Report an issue: GitHub.