{"record":{"id":"0f94fff5e85628db","repo":"nautechsystems/nautilus_trader","slug":"no-durable-store-configured-for-execution-reconcil","errorCode":null,"errorMessage":"No durable store configured for execution reconciliation","messagePattern":"No durable store configured for execution reconciliation","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":909,"sourceCode":"        Ok(SwapPlan {\n            order,\n            quote_currency,\n            pool,\n            instrument_id,\n            pool_address,\n            router: Address::from_str(&intent.transaction_to)?,\n            token_in,\n            token_out,\n            fee,\n            amount_in,\n            min_amount_out: U256::ZERO,\n            profiler_block: intent.created_block,\n        })\n    }\n\n    async fn reconcile_unresolved_execution(&self) -> anyhow::Result<()> {\n        let database = self.cache.database.clone().ok_or_else(|| {\n            anyhow::anyhow!(\"No durable store configured for execution reconciliation\")\n        })?;\n        let wallet_address = self.wallet_address.to_string();\n        let Some(intent) = database\n            .get_active_execution_intent(self.chain.chain_id, &wallet_address)\n            .await?\n        else {\n            return Ok(());\n        };\n        anyhow::ensure!(\n            intent.schema_version == crate::execution::transaction::EXECUTION_SCHEMA_VERSION,\n            \"Execution intent {} uses unsupported schema version {}\",\n            intent.id,\n            intent.schema_version\n        );\n\n        if matches!(intent.status.as_str(), \"prepared\" | \"signed\") {\n            database\n                .mark_execution_intent_recoverable(intent.id)","sourceCodeStart":891,"sourceCodeEnd":927,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/execution/client.rs#L891-L927","documentation":"reconcile_unresolved_execution (crates/adapters/blockchain/src/execution/client.rs:907) fails closed when cache.database is None: crash recovery of in-flight execution requires the durable intent store, so reconciliation without it is refused rather than skipped. In the normal flow connect() guards this call with cache.has_database() (the store is attached only when postgres_cache_database_config is set), so hitting the error means the method ran against a store-less cache - a direct invocation, a reconfigured client, or a code path that bypassed connect().","triggerScenarios":"Invoking reconcile_unresolved_execution on a client whose config omitted postgres_cache_database_database style options (postgres_cache_database_config: None), so connect() never attached a store; calling reconciliation manually on a freshly constructed, unconnected client; config where Postgres options failed to parse and the field defaulted to None.","commonSituations":"Missing Postgres environment variables in recovery tooling; ops scripts constructing a client just to reconcile without wiring the durable store; deployments that previously ran without persistence now attempting reconciliation.","solutions":["Set BlockchainExecutionClientConfig::postgres_cache_database_config before constructing the client.","Call connect() and let it drive reconciliation itself - it attaches the store and calls this method with the guard in place.","Verify cache.has_database() is true before any manual reconciliation call.","Check connect() logs for the \"No Postgres cache database configured\" warning to catch the misconfiguration early."],"exampleFix":"// before\nlet config = BlockchainExecutionClientConfig {\n    postgres_cache_database_config: None,\n    ..Default::default()\n};\n// client.reconcile_unresolved_execution() -> \"No durable store configured for execution reconciliation\"\n\n// after\nlet config = BlockchainExecutionClientConfig {\n    postgres_cache_database_config: Some(postgres_connect_options),\n    ..Default::default()\n};\n// connect() attaches the store and runs reconciliation guarded by has_database()","handlingStrategy":"validation","validationCode":"// Rust: reconciliation needs the durable store - verify before calling\nanyhow::ensure!(\n    client.cache.has_database(),\n    \"reconciliation requires postgres_cache_database_config\"\n);","typeGuard":"fn is_no_durable_store_for_reconciliation(e: &anyhow::Error) -> bool {\n    e.to_string()\n        .contains(\"No durable store configured for execution reconciliation\")\n}","tryCatchPattern":"match client.reconcile_unresolved_execution().await {\n    Ok(()) => {}\n    Err(e) if is_no_durable_store_for_reconciliation(&e) => {\n        // configuration defect: attach Postgres and reconnect; do not skip reconciliation\n        return Err(e.context(\"set postgres_cache_database_config before recovery\"));\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Let connect() own reconciliation - it guards with has_database() and attaches the store.","Any custom recovery tooling must construct the client with Postgres options too.","Assert has_database() in startup health checks for deployments that trade."],"tags":["postgres","reconciliation","configuration","durable-store","rust"],"backgroundTag":"database-not-configured","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}