{"record":{"id":"614fccef1cf060e3","repo":"nautechsystems/nautilus_trader","slug":"persisted-swap-instrument-instrument-id-does-not","errorCode":null,"errorMessage":"Persisted swap instrument {instrument_id} does not match restored order instrument {}","messagePattern":"Persisted swap instrument (.+?) does not match restored order instrument (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":840,"sourceCode":"                .ok_or_else(|| anyhow::anyhow!(\"Persisted swap intent has no client order ID\"))?,\n        )?;\n        let order = self\n            .core\n            .cache()\n            .try_order_owned(&client_order_id)\n            .with_context(|| {\n                format!(\n                    \"Cannot reconcile swap intent {} because order {client_order_id} is not restored\",\n                    intent.id\n                )\n            })?;\n        let instrument_id = InstrumentId::from_str(\n            intent\n                .instrument_id\n                .as_deref()\n                .ok_or_else(|| anyhow::anyhow!(\"Persisted swap intent has no instrument ID\"))?,\n        )?;\n        anyhow::ensure!(\n            order.instrument_id() == instrument_id,\n            \"Persisted swap instrument {instrument_id} does not match restored order instrument {}\",\n            order.instrument_id()\n        );\n        anyhow::ensure!(\n            intent.trader_id.as_deref() == Some(order.trader_id().as_str()),\n            \"Persisted swap trader does not match restored order\"\n        );\n        anyhow::ensure!(\n            intent.strategy_id.as_deref() == Some(order.strategy_id().as_str()),\n            \"Persisted swap strategy does not match restored order\"\n        );\n        anyhow::ensure!(\n            intent.account_id.as_deref() == Some(self.core.account_id.as_str()),\n            \"Persisted swap account does not match execution client account\"\n        );\n\n        let pool = self.resolve_pool(&instrument_id)?;","sourceCodeStart":822,"sourceCodeEnd":858,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/execution/client.rs#L822-L858","documentation":"restore_swap_plan (crates/adapters/blockchain/src/execution/client.rs:840) cross-checks the persisted intent's instrument_id against the instrument of the order restored from the cache under the intent's client_order_id. A mismatch means the durable intent and the live order disagree about which market the swap targeted - a split-brain state the client refuses to reconcile blindly, because completing the swap would emit fills against the wrong instrument. The mismatch check protects order-event integrity after restarts.","triggerScenarios":"The same ClientOrderId was reused on a different instrument across runs while an old intent for it was still active; the order cache was restored from a session whose instrument mapping differs from the one recorded in the intent; stale intents surviving a reconfiguration that renamed or remapped instruments/pools.","commonSituations":"Restarting with changed instrument configuration (different pool set or naming) while intents from the prior configuration remain active; client order id schemes that collide across deployments.","solutions":["Compare both sides: the intent's instrument_id column vs the instrument on the order named by its client_order_id.","Settle the stale intent - verify the on-chain transaction outcome and mark the intent resolved so reconciliation skips it.","Make client order ids unique per instrument and deployment to prevent cross-instrument reuse.","Keep instrument/pool configuration stable across restarts that carry active intents."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"-- Pre-flight: active swap intents whose recorded instrument no longer matches\n-- the orders you will restore (compare against your current instrument config)\nSELECT id, client_order_id, instrument_id, status\nFROM execution_intent\nWHERE status IN ('prepared', 'signed', 'submitted')\n  AND purpose = 'swap';","typeGuard":"fn is_instrument_mismatch(e: &anyhow::Error) -> bool {\n    e.to_string().contains(\"does not match restored order instrument\")\n}","tryCatchPattern":"if let Err(e) = client.connect().await {\n    if is_instrument_mismatch(&e) {\n        // durable intent and restored order disagree: do not trade; reconcile data first\n        log::error!(\"split-brain swap intent (instrument): {e}\");\n    }\n    return Err(e);\n}","preventionTips":["Keep instrument definitions stable across restarts that carry active intents.","Never reuse a ClientOrderId on a different instrument.","Drain or resolve active intents before changing instrument/pool configuration."],"tags":["reconciliation","instrument","state-mismatch","data-integrity","rust"],"backgroundTag":"persisted-state-mismatch","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}