{"record":{"id":"66412fa435fa2e12","repo":"nautechsystems/nautilus_trader","slug":"account-summary-currency-was-empty","errorCode":null,"errorMessage":"Account summary currency was empty","messagePattern":"Account summary currency was empty","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/adapters/interactive_brokers/src/execution/account.rs","lineNumber":563,"sourceCode":"            // Available funds - this is the free amount\n            AccountBalance::from_total_and_free(balance, balance, currency).map_err(Into::into)\n        }\n        _ => {\n            // Default: treat as total balance\n            AccountBalance::from_total_and_locked(balance, Decimal::ZERO, currency)\n                .map_err(Into::into)\n        }\n    }\n}\n\nfn parse_balance_decimal(value: &str) -> anyhow::Result<Decimal> {\n    value\n        .parse::<Decimal>()\n        .context(format!(\"Failed to parse balance value: {}\", value))\n}\n\nfn parse_currency(currency: &str) -> anyhow::Result<Currency> {\n    anyhow::ensure!(!currency.is_empty(), \"Account summary currency was empty\");\n    Ok(Currency::from(currency))\n}\n\n#[cfg(test)]\nmod tests {\n    use ibapi::accounts::AccountSummary;\n    use nautilus_model::types::{AccountBalance, Currency, MarginBalance, Money};\n    use rstest::rstest;\n    use rust_decimal::Decimal;\n\n    use super::{\n        AccountSummaryTags, check_external_position_change, create_position_tracker,\n        merge_account_summary_balance, merge_account_summary_margin, parse_currency,\n    };\n\n    fn margin_summary(tag: &str, value: &str, currency: &str) -> AccountSummary {\n        AccountSummary {\n            account: \"DU123\".to_string(),","sourceCodeStart":545,"sourceCodeEnd":581,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/interactive_brokers/src/execution/account.rs#L545-L581","documentation":"parse_currency is a helper that converts an IB account summary currency string into a Nautilus Currency, and it uses anyhow::ensure! to reject empty strings with this message. IB sometimes emits account summary rows with a blank currency, and this guard prevents constructing a meaningless Currency. Callers (merge_account_summary_margin, merge_account_summary_balance, parse_account_summary_to_balance) log a warning and skip the row rather than propagate the error.","triggerScenarios":"Any account summary update where AccountSummary.currency is an empty string — parse_account_summary_to_balance, merge_account_summary_balance, or merge_account_summary_margin encounter such a row while processing subscribe_account_summary results.","commonSituations":"IB sends summary rows for tags that are not currency-denominated (e.g. AccountType, AvailableFunds variants, or cash balance rows with blank currency) during initial subscription or after account changes.","solutions":["Filter AccountSummary rows to currency-denominated tags and skip rows with empty currency before calling the merge/parse helpers.","Check the raw IB summary data for rows with blank currency and confirm they are expected placeholders.","If currency-denominated rows have empty currency, verify the IB account subscription parameters (account_id, report type) are correct."],"exampleFix":"// before\nlet currency = parse_currency(&summary.currency)?;\n// after\nif summary.currency.is_empty() {\n    tracing::debug!(\"Skipping account summary row with empty currency: {}\", summary.tag);\n    return Ok(());\n}\nlet currency = parse_currency(&summary.currency)?;","handlingStrategy":"validation","validationCode":"fn has_valid_currency(summary: &AccountSummary) -> bool {\n    !summary.currency.is_empty()\n}","typeGuard":null,"tryCatchPattern":"match parse_currency(&summary.currency) {\n    Ok(c) => proceed(c),\n    Err(e) => tracing::debug!(\"Skipping row: {}\", e),\n}","preventionTips":["Filter non-currency-denominated IB summary tags before parsing.","Skip-and-log rows with empty currency instead of treating them as hard failures.","Subscribe only to tags the adapter actually consumes."],"tags":["validation","interactive-brokers","currency","empty-string"],"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"}