{"record":{"id":"0a580582a4d7a421","repo":"nautechsystems/nautilus_trader","slug":"serialized-account-event-has-no-balances","errorCode":null,"errorMessage":"Serialized account event has no balances","messagePattern":"Serialized account event has no balances","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/queries.rs","lineNumber":1114,"sourceCode":"        if updated {\n            let exists =\n                Self::check_if_account_event_exists(pool, account_event.account_id).await?;\n\n            if !exists {\n                anyhow::bail!(\n                    \"Account event does not exist for account: {}\",\n                    account_event.account_id\n                );\n            }\n        }\n\n        let mut transaction = pool.begin().await?;\n        let event = serde_json::to_value(&account_event)\n            .map_err(|e| anyhow::anyhow!(\"Failed to serialize account event: {e}\"))?;\n        let balances = event\n            .get(\"balances\")\n            .cloned()\n            .ok_or_else(|| anyhow::anyhow!(\"Serialized account event has no balances\"))?;\n        let margins = event\n            .get(\"margins\")\n            .cloned()\n            .ok_or_else(|| anyhow::anyhow!(\"Serialized account event has no margins\"))?;\n\n        sqlx::query(\n            r#\"\n            INSERT INTO \"account\" (id) VALUES ($1) ON CONFLICT (id) DO NOTHING\n        \"#,\n        )\n        .bind(account_event.account_id.to_string())\n        .execute(&mut *transaction)\n        .await\n        .map(|_| ())\n        .map_err(|e| anyhow::anyhow!(\"Failed to insert into account table: {e}\"))?;\n\n        sqlx::query(r#\"\n            INSERT INTO \"account_event\" (","sourceCodeStart":1096,"sourceCodeEnd":1132,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/queries.rs#L1096-L1132","documentation":"After serializing the AccountState to a JSON value, add_account requires a \"balances\" key to bind into the account_event table. This error means the serialized object contained no \"balances\" field — the AccountState struct's serde representation lacks that key (skipped via #[serde(skip)] or renamed) or serialized to a non-object shape.","triggerScenarios":"add_account receives an AccountState whose Serialize impl omits the balances field — e.g. a custom/renamed serde attribute, a subclassed or hand-rolled event type, or an empty balances vector serialized as a skipped/None field.","commonSituations":"Upgrading NautilusTrader while a cached/stale build still expects the old field name; using a custom AccountState-like type with #[serde(skip_serializing_if)] on balances; deserializing then re-serializing events through a lossy intermediate format that dropped the key.","solutions":["Print or log serde_json::to_value(&account_event) keys to see what fields actually exist.","Confirm you are constructing a genuine AccountState from this crate version whose Serialize includes \"balances\"; rebuild the crate if binaries are stale.","Remove any #[serde(skip_serializing_if)] or rename on the balances field, or pass an explicit empty Vec instead of skipping.","If balances are legitimately absent, persist an empty JSON array rather than omitting the field."],"exampleFix":"// before: field skipped when empty\n#[serde(skip_serializing_if = \"Vec::is_empty\")]\npub balances: Vec<AccountBalance>,\n\n// after: always serialize the key\npub balances: Vec<AccountBalance>,","handlingStrategy":"validation","validationCode":"// confirm the serialized event carries balances\nlet json = serde_json::to_value(&account_event)?;\nassert!(json.get(\"balances\").is_some(), \"AccountState serialization missing 'balances'\");","typeGuard":"fn has_balances(state: &AccountState) -> bool {\n    serde_json::to_value(state)\n        .ok()\n        .and_then(|v| v.get(\"balances\").cloned())\n        .is_some()\n}","tryCatchPattern":"match add_account(&pool, updated, state).await {\n    Err(e) if e.to_string().contains(\"no balances\") => {\n        log::error!(\"event type lost its balances field — check serde attrs/versions\");\n    }\n    other => other?,\n}","preventionTips":["Do not add skip_serializing_if to required fields on account events.","Rebuild after upgrading NautilusTrader so struct and schema stay in sync.","Persist empty Vecs instead of omitting empty collections.","Assert required keys exist in a serialization unit test."],"tags":["account","serialization","missing-field","postgres"],"backgroundTag":"missing-required-argument","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"}