{"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":863,"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":845,"sourceCodeEnd":881,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/execution/client.rs#L845-L881","documentation":"restore_swap_plan (crates/adapters/blockchain/src/execution/client.rs:863) parses the persisted swap intent's pool_address column; a NULL value aborts reconciliation with this error. The pool address is mandatory on swap intents - it identifies the Uniswap-V3-style pool the swap routed through, and is cross-checked next against the pool resolved for the instrument. NULL therefore means incomplete durable state (legacy row, torn write, or manual edit), never a legitimate swap record.","triggerScenarios":"An active swap intent row with NULL pool_address encountered during connect()-time reconciliation; rows written before pool_address persistence was enforced; SQL edits or ETL that nulled the column.","commonSituations":"Schema upgrades carrying old rows forward; restored backups from older versions; manual data surgery on intent tables.","solutions":["Inspect the row: SELECT id, status, pool_address FROM execution_intent WHERE id = <id>.","Verify the transaction outcome on-chain, then mark the intent resolved or recoverable so reconciliation proceeds.","Audit sibling columns (amount_in, client_order_id, instrument_id) in the same row for NULLs.","Ensure the current writer version always persists pool_address for swap intents."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"-- Pre-flight: active swap intents missing the pool address\nSELECT id, status\nFROM execution_intent\nWHERE status IN ('prepared', 'signed', 'submitted')\n  AND purpose = 'swap'\n  AND pool_address IS NULL;","typeGuard":"fn is_missing_pool_address(e: &anyhow::Error) -> bool {\n    e.to_string().contains(\"Persisted swap intent has no pool address\")\n}","tryCatchPattern":"if let Err(e) = client.connect().await {\n    if is_missing_pool_address(&e) {\n        // incomplete durable row: verify on-chain, repair/resolve the intent, then reconnect\n        log::error!(\"swap intent lacks pool address: {e}\");\n    }\n    return Err(e);\n}","preventionTips":["Audit active intents for NULL routing columns before upgrades.","Backfill missing pool addresses from on-chain swap events when preserving history.","Ensure the writer always persists pool_address for swap intents."],"tags":["reconciliation","postgres","pool-address","data-integrity","rust"],"backgroundTag":"missing-required-field","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}