{"record":{"id":"18721d225c480b12","repo":"nautechsystems/nautilus_trader","slug":"persisted-swap-trader-does-not-match-restored-orde","errorCode":null,"errorMessage":"Persisted swap trader does not match restored order","messagePattern":"Persisted swap trader does not match restored order","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":1049,"sourceCode":"            .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)?;\n        let pool_address = Address::from_str(\n            intent\n                .pool_address\n                .as_deref()\n                .ok_or_else(|| anyhow::anyhow!(\"Persisted swap intent has no pool address\"))?,","sourceCodeStart":1031,"sourceCodeEnd":1067,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L1031-L1067","documentation":"During swap-plan restoration after a restart, the blockchain execution client verifies that the trader_id persisted with the execution intent row matches the trader_id of the restored order from the cache. A mismatch means the durable intent and the in-memory order came from different trader identities, so reconciliation is aborted to avoid attributing a persisted swap to the wrong trader. This is a safety invariant: replaying an intent against an order with a different owner could submit trades under incorrect identity.","triggerScenarios":"restore_swap_plan (called from reconcile_unresolved_execution or build_execution_verification_migration) loads an ExecutionIntentRow whose intent.trader_id is None or differs from order.trader_id() for the order identified by intent.client_order_id. Happens when the cache is restored from a different instance/trader_id than the one that persisted the intent (e.g. trader_id changed in config between runs), or the intent row was written by another trader sharing the same database.","commonSituations":"Changing the trader_id in the node configuration after intents were persisted; pointing multiple trader instances at one shared durable store; restoring a cache snapshot from a different deployment; a NULL trader_id column on an old or hand-edited intent row.","solutions":["Make sure the trader_id configured for this node matches the trader_id of the orders and intents in the durable store (revert the config change or use the original trader_id).","Point the cache database at the durable store belonging to this trader (separate DB file/namespace per trader_id) instead of a shared one.","If the intent row is corrupt or stale, clear/resolve the active execution intent for this wallet/chain so reconciliation skips it.","Ensure orders are restored from the same cache snapshot that produced the intents; do not mix cache snapshots across traders."],"exampleFix":"// before (config changed between runs)\ntrader_id = \"TRADER-002\"\n// after (match the trader that persisted the intents)\ntrader_id = \"TRADER-001\"","handlingStrategy":"validation","validationCode":"// Before starting reconciliation, confirm trader identity matches the persisted intents\nlet intent_trader: Option<&str> = intent.trader_id.as_deref();\nlet order_trader = order.trader_id().as_str();\nif intent_trader != Some(order_trader) {\n    eprintln!(\"intent trader {intent_trader:?} != order trader {order_trader}; fix trader_id config before connecting\");\n}","typeGuard":"fn trader_matches(intent: &ExecutionIntentRow, order: &OrderAny) -> bool {\n    intent.trader_id.as_deref() == Some(order.trader_id().as_str())\n}","tryCatchPattern":null,"preventionTips":["Keep trader_id stable across restarts; treat changing it as requiring a clean durable store","Use a separate database per trader_id","Never share one durable store between trader instances","Audit persisted intent rows for NULL identity columns before upgrade"],"tags":["persistence","reconciliation","identity-mismatch","blockchain"],"backgroundTag":"type-mismatch","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}