nautechsystems/nautilus_trader · error

Failed to insert into order_event table: {e}

Error message

Failed to insert into order_event table: {e}

What it means

Wraps the sqlx failure of the final INSERT into the `order_event` table inside `add_order_event`, just before commit. The transaction is aborted implicitly and the caller receives this anyhow-wrapped error. Common causes are constraint violations (PK/duplicate client_order_id+kind), column type mismatches, or connectivity loss.

Source

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

            .bind(order_event.account_id().map(|x| x.to_string()))
            .bind(order_event.position_id().map(|x| x.to_string()))
            .bind(order_event.commission().map(|x| x.to_string()))
            .bind(order_event.ts_event().to_string())
            .bind(order_event.ts_init().to_string())
            .bind(order_event.activation_price().map(|x| x.to_string()))
            .bind(exec_algorithm_params)
            .bind(order_event.tags().map(|x| x.iter().map(ToString::to_string).collect::<Vec<String>>()))
            .bind(order_event.released_price().map(|x| x.to_string()))
            .bind(order_event.protection_price().map(|x| x.to_string()))
            .bind(order_event.due_post_only())
            .bind(order_event.correction_id().map(|x| x.to_string()))
            .bind(order_event.is_reopened())
            .bind(info)
            .bind(order_event.causation_id().map(|x| x.to_string()))
            .execute(&mut *transaction)
            .await
            .map(|_| ())
            .map_err(|e| anyhow::anyhow!("Failed to insert into order_event table: {e}"))?;
        transaction
            .commit()
            .await
            .map_err(|e| anyhow::anyhow!("Failed to commit transaction: {e}"))
    }

    /// Loads all order events for a `client_order_id` via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if the SQL SELECT or deserialization fails.
    pub async fn load_order_events(
        pool: &PgPool,
        client_order_id: &ClientOrderId,
    ) -> anyhow::Result<Vec<OrderEventAny>> {
        sqlx::query_as::<_, OrderEventAnyRow>(r#"SELECT * FROM "order_event" event WHERE event.client_order_id = $1 ORDER BY created_at ASC"#)
        .bind(client_order_id.to_string())
        .fetch_all(pool)

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check `{e}` for a unique/PK violation and deduplicate before inserting (use the existence checks).
  2. Run migrations so the `order_event` schema matches the Rust INSERT column list.
  3. Verify JSON columns (`exec_algorithm_params`, `info`) accept the serialized values.
  4. Retry `add_order_event`; the transaction ensures no partial rows remain.

Example fix

// before
add_order_event(&mut tx, &event, None).await?;
// after
if !check_if_order_initialized_exists(&pool, event.client_order_id()).await? {
    add_order_event(&mut tx, &event, None).await?;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Avoid duplicate inserts by checking first
let exists = sqlx::query(
    r#"SELECT EXISTS(SELECT 1 FROM "order_event" WHERE client_order_id = $1 AND kind = $2)"#)
    .bind(event.client_order_id().to_string())
    .bind(event.kind().to_string())
    .fetch_one(pool).await
    .map(|row| row.get::<bool, _>(0))
    .unwrap_or(false);
if exists { return Ok(()); }

Type guard

fn is_unique_violation(e: &anyhow::Error) -> bool {
    let s = e.to_string();
    s.contains("duplicate key") || s.contains("23505")
}

Try / catch

match add_order_event(&mut tx, &event, client_id).await {
    Ok(()) => {}
    Err(e) if is_unique_violation(&e) => { /* idempotent: already inserted */ }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `add_order_event` when the order_event INSERT violates a primary key/unique constraint (re-adding the same event), a column value exceeds its type/length, or the DB connection drops during the insert.

Common situations: Replaying the same event twice during reconciliation; schema drift between the Rust column list and the migrated table; oversized reason/info payloads; DB failover mid-transaction.

Related errors


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