{"record":{"id":"5911cbba2b7b65ad","repo":"nautechsystems/nautilus_trader","slug":"wallet-balance-snapshot-has-no-native-currency","errorCode":null,"errorMessage":"Wallet balance snapshot has no native currency","messagePattern":"Wallet balance snapshot has no native currency","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/wallet.rs","lineNumber":184,"sourceCode":"    /// # Errors\n    ///\n    /// Returns an error if the snapshot is incomplete, contains duplicate currencies, or a token\n    /// amount cannot be represented as money.\n    pub fn as_account_balances(&self) -> anyhow::Result<Vec<AccountBalance>> {\n        let mut token_balances = self.token_balances.iter().collect::<Vec<_>>();\n        token_balances.sort_unstable_by_key(|balance| balance.token.address);\n        self.account_balances(token_balances)\n    }\n\n    fn account_balances<'a>(\n        &'a self,\n        token_balances: impl IntoIterator<Item = &'a TokenBalance>,\n    ) -> anyhow::Result<Vec<AccountBalance>> {\n        self.validate_token_addresses()?;\n\n        let native_currency = self\n            .native_currency\n            .ok_or_else(|| anyhow::anyhow!(\"Wallet balance snapshot has no native currency\"))?;\n        let mut currencies = HashSet::new();\n        currencies.insert(native_currency.currency);\n\n        let mut balances = Vec::with_capacity(self.token_balances.len() + 1);\n        balances.push(AccountBalance::new_checked(\n            native_currency,\n            Money::zero(native_currency.currency),\n            native_currency,\n        )?);\n\n        for token_balance in token_balances {\n            let total = token_balance.as_money()?;\n            if !currencies.insert(total.currency) {\n                anyhow::bail!(\n                    \"Wallet balance snapshot contains duplicate currency {}\",\n                    total.currency\n                );\n            }","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/wallet.rs#L166-L202","documentation":"account_balances builds a Vec<AccountBalance> from a wallet snapshot, requiring a native currency balance as the first entry. This error means the snapshot's native_currency field is None — the wallet snapshot is incomplete and cannot be converted into account balances. The library throws it because an account balance report without the chain's native asset would be misleading.","triggerScenarios":"Calling as_account_balances() on a WalletBalanceSnapshot created via the empty constructor (or any snapshot) before set_native_currency_balance()/replace_balances() has been called to populate the native balance.","commonSituations":"Querying balances before the first balance snapshot arrives from the adapter; constructing the snapshot manually and forgetting the native currency; a failed native balance fetch leaving the field unset while token balances were updated.","solutions":["Call set_native_currency_balance() (or replace_balances()) before as_account_balances().","Guard with is_token_universe_initialized-style checks / check native currency presence before converting.","Re-request the full balance snapshot from the adapter instead of converting a partial one.","Wait for the wallet's initial snapshot event before consuming account balances."],"exampleFix":"// before\nlet balances = snapshot.as_account_balances()?;\n// after\nif !snapshot.is_token_universe_initialized() { /* or track native presence */ }\nlet balances = match snapshot.as_account_balances() {\n    Ok(b) => b,\n    Err(e) if e.to_string().contains(\"no native currency\") => {\n        tracing::warn!(\"wallet snapshot not yet populated\");\n        return Ok(vec![]);\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"validation","validationCode":"fn snapshot_has_native(snapshot: &WalletBalanceSnapshot) -> bool {\n    snapshot.as_account_balances().is_ok() // or expose/track native_currency presence at construction\n}","typeGuard":null,"tryCatchPattern":"match snapshot.as_account_balances() {\n    Ok(balances) => balances,\n    Err(e) if e.to_string().contains(\"no native currency\") => {\n        tracing::debug!(\"wallet snapshot incomplete; skipping balance report\");\n        Vec::new()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always call set_native_currency_balance() or replace_balances() before reading balances","Only convert snapshots after the adapter's initial balance event","Track whether the snapshot was populated to avoid converting empty state"],"tags":["rust","defi","wallet","invalid-state"],"backgroundTag":"empty-required-field","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"}