nautechsystems/nautilus_trader · error

Failed to assemble account {account_id} from events: {e}

Error message

Failed to assemble account {account_id} from events: {e}

What it means

This error is raised in `load_account` when `AccountAny::from_events` fails to rebuild an `AccountAny` from the persisted account event rows. The events were loaded from the database successfully but the deserialization/assembly into the domain account state failed. It means stored event data is inconsistent with the current event schema or corrupted.

Source

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

    }

    /// Loads and assembles a complete `AccountAny` for `account_id` via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if assembling events or SQL operations fail.
    pub async fn load_account(
        pool: &PgPool,
        account_id: &AccountId,
    ) -> anyhow::Result<Option<AccountAny>> {
        let account_events = Self::load_account_events(pool, account_id).await;
        match account_events {
            Ok(account_events) => {
                if account_events.is_empty() {
                    return Ok(None);
                }
                let account = AccountAny::from_events(&account_events).map_err(|e| {
                    anyhow::anyhow!("Failed to assemble account {account_id} from events: {e}")
                })?;
                Ok(Some(account))
            }
            Err(e) => anyhow::bail!("Failed to load account events: {e}"),
        }
    }

    /// Loads and assembles all `AccountAny` entries via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if loading events or SQL operations fail.
    pub async fn load_accounts(pool: &PgPool) -> anyhow::Result<Vec<AccountAny>> {
        let mut accounts: Vec<AccountAny> = Vec::new();
        let account_ids: Vec<AccountId> = sqlx::query(
            r#"
            SELECT DISTINCT account_id FROM "account_event"
        "#,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the inner `{e}` message to identify which event type/version failed to decode
  2. Re-export or re-generate the account data with a compatible NautilusTrader version
  3. Exclude or repair the corrupt event rows in `account_event` for this account_id
  4. Pin the reader version to match the writer version of the persisted events

Example fix

// before
let account = load_account(&pool, &account_id).await?;
// after
let account = load_account(&pool, &account_id)
    .await
    .map_err(|e| { tracing::error!("assemble account {account_id}: {e:#}"); e })?;
Defensive patterns

Strategy: try-catch

Try / catch

match AccountAny::from_events(&events) {
    Ok(a) => Some(a),
    Err(e) => { tracing::warn!("cannot assemble account {account_id}: {e:#}"); None }
}

Prevention

When it happens

Trigger: Calling `load_account(pool, account_id)` where the account has non-empty events but one of them cannot be deserialized: an event payload written by a newer/older schema version, a truncated or manually edited row, or an unsupported event type stored in `account_event`.

Common situations: Upgrading NautilusTrader and reloading an old database whose event payloads no longer match; hand-edited or partially written rows; loading an account snapshot DB from a different deployment.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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