{"record":{"id":"d154556dbc5b23d1","repo":"nautechsystems/nautilus_trader","slug":"failed-to-insert-into-trader-table-e","errorCode":null,"errorMessage":"Failed to insert into trader table: {e}","messagePattern":"Failed to insert into trader table: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/queries.rs","lineNumber":329,"sourceCode":"    #[expect(\n        clippy::too_many_lines,\n        reason = \"order snapshot persistence maps the full database schema in one transaction\"\n    )]\n    pub async fn add_order_snapshot(pool: &PgPool, snapshot: OrderSnapshot) -> anyhow::Result<()> {\n        let mut transaction = pool.begin().await?;\n\n        // Insert trader if it does not exist\n        // TODO remove this when node and trader initialization is implemented\n        sqlx::query(\n            r#\"\n            INSERT INTO \"trader\" (id) VALUES ($1) ON CONFLICT (id) DO NOTHING\n            \"#,\n        )\n        .bind(snapshot.trader_id.to_string())\n        .execute(&mut *transaction)\n        .await\n        .map(|_| ())\n        .map_err(|e| anyhow::anyhow!(\"Failed to insert into trader table: {e}\"))?;\n\n        sqlx::query(\n            r#\"\n            INSERT INTO \"order\" (\n                id, trader_id, strategy_id, instrument_id, client_order_id, venue_order_id, position_id,\n                account_id, last_trade_id, order_type, order_side, quantity, price, trigger_price,\n                trigger_type, limit_offset, trailing_offset, trailing_offset_type, time_in_force,\n                expire_time, filled_qty, liquidity_side, avg_px, slippage, commissions, status,\n                is_post_only, is_reduce_only, is_quote_quantity, display_qty, emulation_trigger,\n                trigger_instrument_id, contingency_type, order_list_id, linked_order_ids,\n                parent_order_id, exec_algorithm_id, exec_algorithm_params, exec_spawn_id, tags, init_id, ts_init, ts_last,\n                activation_price, created_at, updated_at\n            ) VALUES (\n                $1, $2, $3, $4, $1, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16,\n                $17::TRAILING_OFFSET_TYPE, $18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28,\n                $29, $30, $31, $32, $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43,\n                CURRENT_TIMESTAMP, CURRENT_TIMESTAMP\n            )","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/queries.rs#L311-L347","documentation":"Raised by `add_order_snapshot` in the first step of its two-step transaction: inserting the trader row into the `trader` table fails. The error occurs before the `order` insert, so the whole transaction aborts and nothing is committed. The sqlx error is wrapped in `anyhow` with this message.","triggerScenarios":"Calling `add_order_snapshot(pool, snapshot)` when the `trader` table is missing; the trader_id violates a constraint; a bound value's format is rejected by a column type; or the connection acquired for the transaction drops before the insert completes.","commonSituations":"Fresh database without migrations; re-inserting a trader row that already exists without conflict handling; schema drift between crate versions; network interruption between the app and PostgreSQL during snapshot writes.","solutions":["Inspect the wrapped `{e}` for the underlying constraint or connection error.","Apply schema migrations so the `trader` table exists with expected columns.","Use upsert / ON CONFLICT handling if snapshots for the same trader_id can be written repeatedly.","Check connection stability; if transient, retry the whole `add_order_snapshot` call (the transaction rolled back atomically)."],"exampleFix":"// before\nadd_order_snapshot(&pool, &snapshot).await?;\n\n// after: idempotent retry on failure\nfor attempt in 0..3 {\n    match add_order_snapshot(&pool, &snapshot).await {\n        Ok(()) => break,\n        Err(e) if attempt < 2 && is_connection_error(&e) => continue,\n        Err(e) => return Err(e),\n    }\n}","handlingStrategy":"try-catch","validationCode":"let ok = sqlx::query_scalar::<_, i64>(\n    \"SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'trader'\")\n    .fetch_one(pool).await? > 0;\nif !ok { return Err(anyhow::anyhow!(\"trader table missing: run migrations\")); }","typeGuard":null,"tryCatchPattern":"if let Err(e) = add_order_snapshot(&pool, &snapshot).await {\n    tracing::error!(\"order snapshot not persisted (rolled back): {e:#}\");\n    // Transaction is atomic; safe to retry once connectivity is confirmed.\n    return Err(e);\n}","preventionTips":["Treat snapshot writes as all-or-nothing — never assume partial success.","Idempotently handle existing trader rows before repeated ingestion runs.","Keep migrations applied and in sync with the crate version.","Watch for network interruptions in orchestrated environments (k8s probes, DB failover)."],"tags":["database","postgres","sqlx","transaction","rust"],"backgroundTag":"database-write-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}