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
- 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.
- Verify the connection URL points at the schema version matching this crate build.
- For duplicate-key errors during replays, make the insert idempotent (ON CONFLICT DO NOTHING) or deduplicate events before persisting.
- 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
- Run migrations on every deploy and verify schema version matches the crate build.
- Use ON CONFLICT DO NOTHING for idempotent replay-safe persistence.
- Monitor connection health and enable TCP keepalive on the pool.
- Classify sqlx errors (schema vs constraint vs connectivity) before retrying.
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
- Failed to insert into block table: {e}
- Failed to batch insert into block table: {e}
- Failed to batch insert into pool_event_block table: {e}
- Failed to insert into dex table: {e}
- Failed to insert into pool table: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/548b41a74415dc61.
Report an issue: GitHub.