nautechsystems/nautilus_trader · error

Failed to insert into position_event table: {e}

Error message

Failed to insert into position_event table: {e}

What it means

This is the final INSERT INTO "position_event" inside insert_position_event failing. All 22 bound columns (event id, ids, prices, timestamps, etc.) are bound as strings, so failures are dominated by DB-level causes: connection issues, schema mismatch (missing columns/types after migrations), or constraint violations such as a foreign key on trader_id or a duplicate event id under a unique index.

Source

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

        .bind(event.order_side.to_string())
        .bind(event.last_px.to_string())
        .bind(event.last_qty.to_string())
        .bind(event.liquidity_side.to_string())
        .bind(position_id.to_string())
        .bind(event.commission.map(|commission| commission.to_string()))
        .bind(event.reconciliation)
        .bind(position_event_info)
        .bind(
            event
                .causation_id
                .map(|causation_id| causation_id.to_string()),
        )
        .bind(event.ts_event.to_string())
        .bind(event.ts_init.to_string())
        .execute(&mut **transaction)
        .await
        .map(|_| ())
        .map_err(|e| anyhow::anyhow!("Failed to insert into position_event table: {e}"))
    }

    fn event_position_id(event: &OrderFilled) -> anyhow::Result<PositionId> {
        event.position_id.ok_or_else(|| {
            anyhow::anyhow!(
                "Cannot persist position event with no position_id: {}",
                event.event_id
            )
        })
    }

    /// Inserts or updates an `AccountState` event via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if the SQL INSERT or UPDATE operation fails.
    pub async fn add_account(
        pool: &PgPool,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the embedded sqlx error: 'relation does not exist' or 'column does not exist' means run the latest migrations; 'duplicate key' means the event was already persisted.
  2. Verify the connection URL points at the schema version matching this crate build.
  3. For duplicate-key errors during replays, make the insert idempotent (ON CONFLICT DO NOTHING) or deduplicate events before persisting.
  4. For connection errors, retry the transaction with backoff; check pool limits and server logs.

Example fix

// before: hard failure on replay duplicates
INSERT INTO "position_event" (...) VALUES (...)

// after: idempotent persist
INSERT INTO "position_event" (...) VALUES (...)
ON CONFLICT (id) DO NOTHING
Defensive patterns

Strategy: retry

Validate before calling

// preflight: schema present and no duplicate event id
let schema_ok = sqlx::query("SELECT to_regclass('""position_event""') IS NOT NULL").fetch_one(pool).await?;
let dup = sqlx::query("SELECT 1 FROM \"position_event\" WHERE id = $1")
    .bind(event.event_id.to_string()).fetch_optional(pool).await?;

Try / catch

match persist(&event).await {
    Err(e) if e.to_string().contains("duplicate key") => log::debug!("already persisted: {}", event.event_id),
    Err(e) if is_transient(&e) => retry_with_backoff(|| persist(&event)).await?,
    Err(e) => return Err(e),
    Ok(()) => {},
}

Prevention

When it happens

Trigger: Persisting an OrderFilled event when the position_event INSERT is rejected — schema drift (missing column like liquidity_side or commission after an upgrade), duplicate event_id with a unique constraint, FK violation, dead connection, or a value that cannot be cast to the column type.

Common situations: Upgrading NautilusTrader without re-running DB migrations so the Rust code binds columns the table lacks; replaying historical data into a DB that already contains those event ids; the Postgres connection dropped after a long-running backtest write burst; wrong database pointed to by the connection URL (stale/empty schema).

Related errors


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