{"record":{"id":"be1ffd3bec1243d4","repo":"nautechsystems/nautilus_trader","slug":"persisted-swap-intent-has-no-pool-address","errorCode":null,"errorMessage":"Persisted swap intent has no pool address","messagePattern":"Persisted swap intent has no pool address","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":1067,"sourceCode":"        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\"))?,\n        )?;\n        anyhow::ensure!(\n            pool.address == pool_address,\n            \"Persisted pool {pool_address} does not match restored pool {}\",\n            pool.address\n        );\n        let amount_in = U256::from_str(\n            intent\n                .amount_in\n                .as_deref()\n                .ok_or_else(|| anyhow::anyhow!(\"Persisted swap intent has no input amount\"))?,\n        )?;\n        let fee = U24::try_from(\n            pool.fee\n                .ok_or_else(|| anyhow::anyhow!(\"Restored pool {instrument_id} has no fee\"))?,\n        )?;\n        let quote_token = pool.get_quote_token();\n        let quote_currency = Currency::new_checked(","sourceCodeStart":1049,"sourceCodeEnd":1085,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L1049-L1085","documentation":"When rebuilding a SwapPlan from a persisted execution intent, the pool_address column is required to parse the Uniswap V3 pool contract address. If the intent row has no pool_address (NULL/missing), restore_swap_plan cannot reconstruct the swap target and fails. The library throws this because a swap cannot be safely re-executed without knowing the exact pool it was prepared against.","triggerScenarios":"reconcile_unresolved_execution (via connect) or build_execution_verification_migration loads an active ExecutionIntentRow whose intent.pool_address is None and calls restore_swap_plan. Occurs with rows written by older schema versions, partially-written rows, or manual database edits.","commonSituations":"Upgrading the adapter from a version that did not persist pool_address while old intent rows remain in the durable store; an interrupted/partial insert; cleaning or migrating the DB by hand and dropping the column value.","solutions":["Let the stale intent be marked recoverable/resolved (or delete the row) so reconciliation skips it; it cannot be rebuilt without the pool address.","Backfill pool_address on the intent row from the original trade records if the swap must still be reconciled.","Check the schema_version of the row; rows from older schemas should be migrated or discarded per the adapter's migration path.","Avoid hand-editing the durable store; always persist intents through the adapter so required fields are set."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if intent.pool_address.is_none() {\n    eprintln!(\"intent {} lacks pool_address; it cannot be restored - resolve/clear it before reconnect\", intent.id);\n}","typeGuard":"fn has_pool_address(intent: &ExecutionIntentRow) -> bool {\n    intent.pool_address.as_deref().map(|s| !s.is_empty()).unwrap_or(false)\n}","tryCatchPattern":"// Wrap reconciliation per-intent and treat missing-column rows as unrecoverable\nmatch restore_swap_plan(&intent) {\n    Err(e) if e.to_string().contains(\"no pool address\") => mark_intent_recoverable(&intent),\n    Err(e) => return Err(e),\n    Ok(plan) => drive(plan),\n}","preventionTips":["Never hand-edit or partially insert rows in the execution intent table","Run schema migrations before starting the adapter against an old database","Confirm intent.schema_version matches the adapter's EXECUTION_SCHEMA_VERSION","Persist intents only through the adapter API"],"tags":["persistence","missing-field","reconciliation","uniswap-v3"],"backgroundTag":"empty-required-field","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"}