nautechsystems/nautilus_trader · error
Failed to insert into order table: {e}
Error message
Failed to insert into order table: {e} What it means
Raised by `add_order_snapshot` on the second step of its transaction: the INSERT into the `"order"` table fails. At this point the trader-table insert already succeeded, but since the transaction is never committed it is rolled back, so no partial data is persisted. The sqlx error is wrapped in `anyhow` with this message.
Source
Thrown at crates/infrastructure/src/sql/queries.rs:451
.bind(snapshot.contingency_type.map_or_else(
|| "NO_CONTINGENCY".to_string(),
|value| value.to_string(),
))
.bind(snapshot.order_list_id.map(|x| x.to_string()))
.bind(snapshot.linked_order_ids.map(|x| x.iter().map(ToString::to_string).collect::<Vec<String>>()))
.bind(snapshot.parent_order_id.map(|x| x.to_string()))
.bind(snapshot.exec_algorithm_id.map(|x| x.to_string()))
.bind(snapshot.exec_algorithm_params.map(|x| serde_json::to_value(x).unwrap()))
.bind(snapshot.exec_spawn_id.map(|x| x.to_string()))
.bind(snapshot.tags.map(|x| x.iter().map(ToString::to_string).collect::<Vec<String>>()))
.bind(snapshot.init_id.to_string())
.bind(snapshot.ts_init.to_string())
.bind(snapshot.ts_last.to_string())
.bind(snapshot.activation_price.map(|x| x.to_string()))
.execute(&mut *transaction)
.await
.map(|_| ())
.map_err(|e| anyhow::anyhow!("Failed to insert into order table: {e}"))?;
transaction
.commit()
.await
.map_err(|e| anyhow::anyhow!("Failed to commit transaction: {e}"))
}
/// Loads an `OrderSnapshot` entry by client order ID via the provided `pool`.
///
/// # Errors
///
/// Returns an error if the SQL SELECT or deserialization fails.
pub async fn load_order_snapshot(
pool: &PgPool,
client_order_id: &ClientOrderId,
) -> anyhow::Result<Option<OrderSnapshot>> {
sqlx::query_as::<_, OrderSnapshotRow>(r#"SELECT * FROM "order" WHERE client_order_id = $1"#)
.bind(client_order_id.to_string())View on GitHub (pinned to 18893faf8b)
Solutions
- Read the wrapped `{e}` to identify the exact constraint or type error.
- Ensure migrations have created the `"order"` table with the expected schema.
- Avoid duplicate writes: check `load_order_snapshot` first or add ON CONFLICT handling for client_order_id.
- Verify optional fields (price, trigger_price, venue_order_id) match column nullability and types.
Example fix
// before: blindly inserting duplicates
add_order_snapshot(&pool, &snapshot).await?;
// after: skip if already persisted
if load_order_snapshot(&pool, snapshot.client_order_id).await?.is_none() {
add_order_snapshot(&pool, &snapshot).await?;
} Defensive patterns
Strategy: validation
Validate before calling
// Avoid the most common cause: duplicate client_order_id
let dup = sqlx::query_scalar::<_, i64>(
"SELECT COUNT(*) FROM \"order\" WHERE client_order_id = $1")
.bind(snapshot.client_order_id.to_string())
.fetch_one(pool).await? > 0;
if dup { return Ok(()); } Try / catch
match add_order_snapshot(&pool, &snapshot).await {
Ok(()) => (),
Err(e) if format!("{e:#}").contains("duplicate key") => {
tracing::warn!("snapshot already exists for {}", snapshot.client_order_id);
}
Err(e) => return Err(e),
} Prevention
- Check for an existing snapshot (load_order_snapshot) before writing.
- Ensure order_type/order_side values match DB enum/CHECK constraints.
- Verify optional fields (price, trigger_price, venue_order_id) match column nullability.
- Apply schema migrations before replay/ingestion jobs.
When it happens
Trigger: Calling `add_order_snapshot` when: the `"order"` table is missing; a required column is NULL (e.g. venue_order_id, position_id constraints); a value exceeds a column's length/precision; a bound value's string form fails to parse into the column type; or a unique constraint on client_order_id is violated by a duplicate snapshot.
Common situations: Writing the same order snapshot twice during replay recovery; migrations not applied; enum-like values (order_type, order_side) written as strings not matching the DB enum/CHECK constraints; schema changed after a crate upgrade so bind count/types mismatch.
Related errors
- Failed to insert into trader table: {e}
- Failed to insert into position table: {e}
- Failed to delete position_event rows: {e}
- Failed to start replacement transaction persistence: {e}
- Failed to retire replaced execution hash: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/dad0f14b956c09e6.
Report an issue: GitHub.