nautechsystems/nautilus_trader · error

Serialized account event has no margins

Error message

Serialized account event has no margins

What it means

Identical in structure to the balances check: add_account extracts the "margins" key from the serialized AccountState and errors when it is missing, because the account_event INSERT binds margins in column $6. It fires when the event's serde representation has no "margins" field.

Source

Thrown at crates/infrastructure/src/sql/queries.rs:1118

            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(|_| ())
        .map_err(|e| anyhow::anyhow!("Failed to insert into account table: {e}"))?;

        sqlx::query(r#"
            INSERT INTO "account_event" (
                id, kind, account_id, base_currency, balances, margins, is_reported, ts_event, ts_init, created_at, updated_at
            ) VALUES (
                $1, $2, $3, $4, $5, $6, $7, $8, $9, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP
            )

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the serialized event's keys (serde_json::to_value) to confirm margins is absent.
  2. Ensure AccountState is built from the current crate version whose Serialize emits "margins"; rebuild stale artifacts.
  3. Remove skip/rename serde attributes on margins, or always pass an explicit empty Vec.
  4. If the account type genuinely has no margins, persist an empty array/JSON null-compatible value instead of omitting the key.

Example fix

// before: margins omitted for cash accounts
#[serde(skip_serializing_if = "Vec::is_empty")]
pub margins: Vec<MarginBalance>,

// after: always emit the key
pub margins: Vec<MarginBalance>,
Defensive patterns

Strategy: validation

Validate before calling

let json = serde_json::to_value(&account_event)?;
assert!(json.get("margins").is_some(), "AccountState serialization missing 'margins'");

Type guard

fn has_margins(state: &AccountState) -> bool {
    serde_json::to_value(state)
        .ok()
        .and_then(|v| v.get("margins").cloned())
        .is_some()
}

Try / catch

match add_account(&pool, updated, state).await {
    Err(e) if e.to_string().contains("no margins") => {
        log::error!("event type lost its margins field — check serde attrs/versions");
    }
    other => other?,
}

Prevention

When it happens

Trigger: add_account with an AccountState whose serialized form omits "margins" — custom serde attributes (skip/rename) on the margins field, a hand-built or older event type, or a round-trip through a format that dropped the key.

Common situations: Margin accounts not yet supported by a custom adapter so margins was removed/skipped; stale build after an upstream rename of the field; events reconstructed from external storage without margins and re-persisted.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/bfd608c034326dad. Report an issue: GitHub.