nautechsystems/nautilus_trader · error
Failed to serialize account event: {e}
Error message
Failed to serialize account event: {e} What it means
add_account serializes the whole AccountState event to serde_json::Value and then picks out the "balances" and "margins" keys. This error means serde_json::to_value(&account_event) itself returned Err. Since AccountState derives Serialize, this is rare and typically indicates a custom or poisoned serialization path (e.g. an f64 NaN/Infinity in an override, or a broken custom Serialize impl for a contained type).
Source
Thrown at crates/infrastructure/src/sql/queries.rs:1110
pool: &PgPool,
updated: bool,
account_event: AccountState,
) -> anyhow::Result<()> {
if updated {
let exists =
Self::check_if_account_event_exists(pool, account_event.account_id).await?;
if !exists {
anyhow::bail!(
"Account event does not exist for account: {}",
account_event.account_id
);
}
}
let mut transaction = pool.begin().await?;
let event = serde_json::to_value(&account_event)
.map_err(|e| anyhow::anyhow!("Failed to serialize account event: {e}"))?;
let balances = event
.get("balances")
.cloned()
.ok_or_else(|| anyhow::anyhow!("Serialized account event has no balances"))?;
let margins = event
.get("margins")
.cloned()
.ok_or_else(|| anyhow::anyhow!("Serialized account event has no margins"))?;
sqlx::query(
r#"
INSERT INTO "account" (id) VALUES ($1) ON CONFLICT (id) DO NOTHING
"#,
)
.bind(account_event.account_id.to_string())
.execute(&mut *transaction)
.await
.map(|_| ())View on GitHub (pinned to 18893faf8b)
Solutions
- Read the embedded serde error message to identify the offending field/type in the AccountState.
- Sanitize balances/margins before constructing the AccountState: reject or replace NaN/infinite values.
- Fix or replace the custom Serialize impl that returns Err.
- Align serde_json versions in the dependency tree (cargo tree -i serde_json) if the failure stems from version mismatch.
Example fix
// before: NaN balances blow up during serialization
let state = AccountState { balances: vec![balance_with(nan_price)], .. };
// after: validate before persisting
assert!(state.balances.iter().all(|b| b.total.is_finite()), "non-finite balance");
add_account(&pool, updated, state).await?; Defensive patterns
Strategy: validation
Validate before calling
// dry-run serialization before calling add_account
serde_json::to_value(&account_event)
.expect("AccountState must serialize: check for NaN/Inf balances or bad custom Serialize impl"); Type guard
fn is_serializable_account(state: &AccountState) -> bool {
serde_json::to_value(state).is_ok()
} Try / catch
let json = serde_json::to_value(&account_event)
.map_err(|e| { log::error!("account serialization failed: {e}"); e })?; Prevention
- Reject non-finite balance/margin values when constructing AccountState.
- Keep serde_json versions unified across the dependency tree.
- Add a round-trip (serialize then deserialize) test for AccountState.
- Avoid custom Serialize impls on types embedded in account events.
When it happens
Trigger: Calling add_account (or the higher-level cache write_account/adapter) with an AccountState whose serialization to JSON fails — custom Serialize implementations returning Err, or serde_json configured in a mode where non-finite floats hard-error.
Common situations: A custom account event type or Decimal-like type whose Serialize impl can fail; NaN or infinite balance values flowing through a serde_json build that rejects them; mixing serde_json versions across the dependency graph.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- Failed to serialize exec algorithm params: {e}
- Failed to serialize order event info: {e}
- Failed to serialize fill info: {e}
- CustomData must be valid JSON: {e}
- Failed to serialize JSON: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/924b51f152bb6f75.
Report an issue: GitHub.