{"record":{"id":"8d037683c9699448","repo":"nautechsystems/nautilus_trader","slug":"order-client-order-id-is-already-claimed-by-exec","errorCode":null,"errorMessage":"Order {client_order_id} is already claimed by execution client {conflicting_client_id} and cannot be claimed by {client_id}","messagePattern":"Order (.+?) is already claimed by execution client (.+?) and cannot be claimed by (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/queries.rs","lineNumber":1369,"sourceCode":"        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\n            .map_err(|e| anyhow::anyhow!(\"Failed to persist execution client {client_id}: {e}\"))?;\n\n            let result = sqlx::query(","sourceCodeStart":1351,"sourceCodeEnd":1387,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/d1527c24afdf475115785557f89a55c3e336c51f/crates/infrastructure/src/sql/queries.rs#L1351-L1387","documentation":"During Postgres cache setup, index_order_clients (crates/infrastructure/src/sql/queries.rs:1345) claims persisted order_event rows for an execution client, backing the external_order_claims feature on strategies. Before updating, it selects any order_event row for the client_order_id already tagged with a different non-NULL client_id; if one exists it bails, because two execution clients must never own the same order.","triggerScenarios":"Node startup (or an explicit index_order_clients call) with external order claims where a claim (ClientOrderId, ClientId) hits order_event rows already attributed to another client_id: configuring claims under a different execution client than the one that submitted the orders, or two strategies/configs claiming the same client_order_id through different clients.","commonSituations":"Changing the execution client ID configured for external order claims between runs without re-attributing database rows; copying a node configuration to another machine with a different client_id; both a venue client and a different client name claiming the same orders; renaming client IDs in config after orders were persisted.","solutions":["Configure external_order_claims with the same ClientId as the execution client that originally submitted those orders.","Inspect existing ownership: SELECT DISTINCT client_id FROM order_event WHERE client_order_id = '...'; and reconcile the config to it.","If re-assignment is genuinely intended, repair the persisted client_id on those order_event rows deliberately (backup first) or start with a clean database.","Ensure exactly one node/strategy claims any given client_order_id."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"-- Run before starting the node with external_order_claims\nSELECT client_order_id, DISTINCT_ON (client_order_id) client_id\nFROM order_event\nWHERE client_order_id = ANY($1)  -- your claimed order ids\n  AND client_id IS NOT NULL\nORDER BY client_order_id, created_at DESC;\n-- If any returned client_id differs from your configured ClientId, fix the config first.","typeGuard":null,"tryCatchPattern":"if let Err(e) = node_builder.build().await {\n    let msg = e.to_string();\n    if msg.contains(\"already claimed by execution client\") {\n        log::error!(\"external order claim conflicts with persisted ownership: {msg}\");\n        // reconcile claim client_id with the persisted client_id before restarting\n    }\n}","preventionTips":["Keep the ClientId in external_order_claims identical to the client that submitted the orders.","Audit persisted client_id ownership with a one-line SQL query before changing claim configs.","Never let two nodes or two client IDs claim the same client_order_id.","Snapshot/backup the order_event table before any manual re-attribution."],"tags":["postgres","cache","external-order-claims","client-id"],"backgroundTag":"order-ownership-conflict","analyzedSha":"d1527c24afdf475115785557f89a55c3e336c51f","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-29T07:17:48.351Z"}