{"record":{"id":"a172466b872bf1cd","repo":"nautechsystems/nautilus_trader","slug":"failed-to-validate-order-client-origin-e","errorCode":null,"errorMessage":"Failed to validate order client origin: {e}","messagePattern":"Failed to validate order client origin: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/queries.rs","lineNumber":1461,"sourceCode":"\n        let mut transaction = pool.begin().await?;\n\n        for (client_order_id, client_id) in claims {\n            let conflicting_client_id = sqlx::query_scalar::<_, String>(\n                r#\"\n                SELECT client_id\n                FROM \"order_event\"\n                WHERE client_order_id = $1\n                  AND client_id IS NOT NULL\n                  AND client_id <> $2\n                LIMIT 1\n            \"#,\n            )\n            .bind(client_order_id.to_string())\n            .bind(client_id.to_string())\n            .fetch_optional(&mut *transaction)\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to validate order client origin: {e}\"))?;\n\n            if let Some(conflicting_client_id) = conflicting_client_id {\n                anyhow::bail!(\n                    \"Order {client_order_id} is already claimed by execution client \\\n                     {conflicting_client_id} and cannot be claimed by {client_id}\"\n                );\n            }\n\n            sqlx::query(\n                r#\"\n                INSERT INTO \"client\" (id)\n                VALUES ($1)\n                ON CONFLICT (id) DO NOTHING\n            \"#,\n            )\n            .bind(client_id.to_string())\n            .execute(&mut *transaction)\n            .await","sourceCodeStart":1443,"sourceCodeEnd":1479,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/queries.rs#L1443-L1479","documentation":"index_order_clients first checks whether a client_order_id is already claimed by a different execution client; any sqlx failure during that fetch_optional lookup is wrapped as 'Failed to validate order client origin'. It is a database-layer failure of the conflict-check SELECT, not the conflict itself (that is the separate bail below). Thrown so the whole transaction aborts with a clear message.","triggerScenarios":"Calling index_order_clients when the SELECT used for the conflicting-client check fails: `order_event`/related table missing, malformed query/schema mismatch, transaction connection lost, or lock timeouts.","commonSituations":"Cache DB not initialized before rebuild_index/connect; concurrent writers holding locks on order_event rows; DB connection dropped mid-transaction.","solutions":["Inspect the error's source chain for the raw sqlx/DB message.","Initialize the cache schema (order_event, client tables) before calling index_order_clients.","Retry on transient connection/lock errors; reduce concurrency or shorten the transaction.","Verify the transaction was opened on a healthy connection."],"exampleFix":"// before\nqueries::postgres::index_order_clients(&mut tx, client_order_id, client_id).await?;\n// after\nmatch queries::postgres::index_order_clients(&mut tx, client_order_id, client_id).await {\n    Ok(()) => (),\n    Err(e) if is_transient(&e) => retry_indexing(client_order_id, client_id).await?,\n    Err(e) => return Err(e),\n}","handlingStrategy":"retry","validationCode":"let db_ready = sqlx::query(r#\"SELECT 1 FROM \\\"order_event\\\" LIMIT 1\"#).fetch_optional(pool).await.is_ok();\nanyhow::ensure!(db_ready, \"order_event schema missing before index_order_clients\");","typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match index_clients_once(&pool, &client_order_id, &client_id).await {\n        Ok(_) => break,\n        Err(e) if is_transient(&e) && attempt < 2 => tokio::time::sleep(backoff(attempt)).await,\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Initialize schema before rebuild_index/connect flows","Serialize index rebuilds; avoid concurrent writers on order_event","Keep transactions short to reduce lock contention","Configure pool timeouts/keepalives for long rebuilds"],"tags":["rust","database","sqlx","transaction","anyhow"],"backgroundTag":"database-query-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"}