{"record":{"id":"fa226fde7f8a438b","repo":"nautechsystems/nautilus_trader","slug":"cannot-persist-account-with-no-events-fa226f","errorCode":null,"errorMessage":"Cannot persist account with no events: {}","messagePattern":"Cannot persist account with no events: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/cache.rs","lineNumber":1318,"sourceCode":"    ) -> anyhow::Result<()> {\n        let mut snapshot = if position.fill_voids.is_empty() {\n            PositionSnapshot::from(position, unrealized_pnl)\n        } else {\n            PositionSnapshot::from_replay_state(position, unrealized_pnl)\n        };\n        snapshot.ts_init = ts_snapshot;\n        self.add_position_snapshot(&snapshot)\n    }\n\n    fn heartbeat(&self, _timestamp: UnixNanos) -> anyhow::Result<()> {\n        todo!()\n    }\n}\n\nfn account_last_event(account: &AccountAny) -> anyhow::Result<AccountState> {\n    account\n        .last_event()\n        .ok_or_else(|| anyhow::anyhow!(\"Cannot persist account with no events: {}\", account.id()))\n}\n\nfn order_initialized_event(order: &OrderAny) -> OrderInitialized {\n    order.init_event().clone()\n}\n\nfn position_last_event(position: &Position) -> anyhow::Result<OrderFilled> {\n    position\n        .last_event()\n        .ok_or_else(|| anyhow::anyhow!(\"Cannot persist position with no events: {}\", position.id))\n}\n\n#[expect(\n    clippy::too_many_lines,\n    reason = \"database command dispatch enumerates each cache query variant explicitly\"\n)]\nasync fn drain_buffer(pool: &PgPool, buffer: &mut VecDeque<DatabaseQuery>) {\n    for cmd in buffer.drain(..) {","sourceCodeStart":1300,"sourceCodeEnd":1336,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/cache.rs#L1300-L1336","documentation":"Raised by `account_last_event` when an `AccountAny` has no events, i.e. `account.last_event()` returns None. The SQL cache persists accounts by writing their latest `AccountState` event via `add_account`/`update_account`; an account with an empty event log cannot be represented in the database, so persisting it is treated as an internal invariant violation and aborted with this anyhow error.","triggerScenarios":"Calling `cache.add_account(account)` or `cache.update_account(account)` (PostgresCacheAdapter) with an account that has never had an `AccountState` event applied: a hand-constructed account object, a deserialized/reconstructed account whose event log was dropped, or an adapter that failed to emit the initial state event.","commonSituations":"Custom broker/adapter code that builds an `AccountAny` manually in tests and registers it with the cache before any state update; restoring accounts from an external system without replaying their initial state event; a bug in an event-generating client that never publishes the first AccountState.","solutions":["Ensure every account receives its initial AccountState event (apply it) before calling add_account/update_account on the cache.","Check account.last_event().is_some() before persisting; if None, skip persistence or defer until the first event arrives.","Trace the account id from the error message to where it was constructed and fix the code path that failed to apply events.","Verify reconstruction/deserialization logic isn't dropping the account's event log."],"exampleFix":"// before\ncache.add_account(&account).await?;\n// after\nif account.last_event().is_some() {\n    cache.add_account(&account).await?;\n} else {\n    tracing::warn!(\"skipping persistence of event-less account {}\", account.id());\n}","handlingStrategy":"validation","validationCode":"if account.last_event().is_none() {\n    return Err(anyhow::anyhow!(\n        \"refusing to persist account {} with no events\",\n        account.id()\n    ));\n}","typeGuard":"fn has_events(account: &AccountAny) -> bool {\n    account.last_event().is_some()\n}","tryCatchPattern":"match cache.add_account(&account).await {\n    Err(e) if e.to_string().contains(\"no events\") => {\n        tracing::warn!(\"skipping event-less account {}: {e}\", account.id());\n    }\n    result => result?,\n}","preventionTips":["Only construct accounts through the event-generating account flow so the initial AccountState event always exists.","Check last_event().is_some() before any cache persistence call.","In restore/replay paths, assert the account event log is non-empty before caching.","Log account.id() alongside persistence failures to speed up tracing the origin."],"tags":["rust","database","cache","account","invariant"],"backgroundTag":"internal-invariant-violation","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"}