nautechsystems/nautilus_trader · error

Failed to persist execution client {client_id}: {e}

Error message

Failed to persist execution client {client_id}: {e}

What it means

Within index_order_clients, the INSERT INTO "client" (id) ... ON CONFLICT DO NOTHING for the execution client failed; sqlx error wrapped in anyhow. This step upserts the client row before linking order events, so failure means the `client` table is missing/mismatched or the transaction connection broke. The transaction is aborted as a result.

Source

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

            if let Some(conflicting_client_id) = conflicting_client_id {
                anyhow::bail!(
                    "Order {client_order_id} is already claimed by execution client \
                     {conflicting_client_id} and cannot be claimed by {client_id}"
                );
            }

            sqlx::query(
                r#"
                INSERT INTO "client" (id)
                VALUES ($1)
                ON CONFLICT (id) DO NOTHING
            "#,
            )
            .bind(client_id.to_string())
            .execute(&mut *transaction)
            .await
            .map_err(|e| anyhow::anyhow!("Failed to persist execution client {client_id}: {e}"))?;

            let result = sqlx::query(
                r#"
                UPDATE "order_event"
                SET client_id = $2
                WHERE client_order_id = $1
                  AND (client_id IS NULL OR client_id = $2)
            "#,
            )
            .bind(client_order_id.to_string())
            .bind(client_id.to_string())
            .execute(&mut *transaction)
            .await
            .map_err(|e| anyhow::anyhow!("Failed to index order client origin: {e}"))?;

            if result.rows_affected() == 0 {
                anyhow::bail!("No persisted order events found for {client_order_id}");
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the chained sqlx error to identify missing table vs connection failure.
  2. Run the full cache schema initialization so the `client` table exists.
  3. Check DB connectivity and re-run index_order_clients; the transaction rolls back so it is safe to retry.
  4. Verify the `client.id` column type/size fits your client_id strings.

Example fix

// before
queries::postgres::index_order_clients(&mut tx, &client_order_id, &client_id).await?;
// after
sqlx::query(r#"CREATE TABLE IF NOT EXISTS "client" (id VARCHAR PRIMARY KEY)"#)
    .execute(&mut *tx).await?;
queries::postgres::index_order_clients(&mut tx, &client_order_id, &client_id).await?;
Defensive patterns

Strategy: validation

Validate before calling

let client_table = sqlx::query(r#"SELECT 1 FROM \"client\" LIMIT 1"#).fetch_optional(pool).await.is_ok();
anyhow::ensure!(client_table, "client table missing; run cache schema init first");

Try / catch

match queries::postgres::index_order_clients(&mut tx, &client_order_id, &client_id).await {
    Err(e) if e.to_string().contains("Failed to persist execution client") => {
        anyhow::bail!("cache schema incomplete: {e:#}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling index_order_clients when the `client` table does not exist or its `id` column type cannot accept the client_id string, or the DB connection fails during the INSERT.

Common situations: Partially initialized cache DB (order_event exists but client table missing); schema created by an older nautilus version; connection dropped mid-transaction.

Related errors


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