nautechsystems/nautilus_trader · error
No durable store configured for execution reconciliation
Error message
No durable store configured for execution reconciliation
What it means
reconcile_unresolved_execution, run during execution client connect, needs a durable database (cache.database) to inspect and recover persisted execution intents. If no durable store is configured, the client cannot safely detect unfinished swaps or signed transactions and fails the connect flow with this error. The library requires the durable store precisely because recovery of blockchain executions must survive process restarts.
Solutions
- Configure a durable cache database for the execution client (set the cache database in the client/cache config) so intents can be reconciled.
- Use a live-trading node config that includes persistence; the blockchain execution client requires it by design.
- If you truly need no persistence, use an execution client/mode that does not perform durable reconciliation instead of this one.
- Verify the database is actually constructed and attached to the cache before the client connects (check wiring/order of component setup).
Example fix
// before (no database attached) CacheConfig() # in-memory only // after CacheConfig(database=CacheDatabaseConfig(path="~/.nautilus/blockchain.db"))
Defensive patterns
Strategy: validation
Validate before calling
// Before connecting, assert a durable store is wired
if cache.database.is_none() {
panic!("blockchain execution client requires a cache database for reconciliation");
} Type guard
fn has_durable_store(cache: &Cache) -> bool {
cache.database.is_some()
} Try / catch
// Surface the misconfiguration at startup instead of mid-connect
match client.connect().await {
Err(e) if e.to_string().contains("No durable store configured") => {
configure_cache_database()?; client.connect().await?;
}
result => result?,
} Prevention
- Always configure a cache database for live blockchain execution clients
- Add a startup config check that database is present before connect
- Do not reuse backtest/in-memory cache configs for live trading
- Log the database path at boot to confirm wiring
When it happens
Trigger: connect() -> reconcile_unresolved_execution is called while self.cache.database is None, i.e. the cache/database was not attached to the blockchain execution client's cache configuration. Any startup with a cache that has no database backing triggers this immediately.
Common situations: Running the blockchain adapter in a backtest or in-memory setup where no cache database is wired; forgetting to set the cache database config (path/connection) for live trading; explicitly disabling persistence while using an execution client that mandates recovery.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Protected payload keys are required for execution recovery
- Execution intent has no persisted signed transaction bytes
- Lighter execution client requires credentials; set…
- Persisted pool does not match restored pool
- Persisted swap account does not match execution client…
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/0f94fff5e85628db.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/blockchain/src/execution/client.rs:1126
instrument_id,
pool_address,
router: Address::from_str(&intent.transaction_to)?,
factory,
weth: self.weth_address,
token_in,
token_out,
fee,
amount_in,
min_amount_out: U256::ZERO,
slippage_bps: 0,
quote_spend_ceiling: None,
profiler_position: None,
})
}
async fn reconcile_unresolved_execution(&self) -> anyhow::Result<()> {
let database = self.cache.database.clone().ok_or_else(|| {
anyhow::anyhow!("No durable store configured for execution reconciliation")
})?;
let _payload_lease = database
.acquire_execution_payload_lease(self.payload_keys.as_deref().ok_or_else(|| {
anyhow::anyhow!("Protected payload keys are required for execution recovery")
})?)
.await?;
let wallet_address = self.wallet_address.to_string();
anyhow::ensure!(
!database
.has_recoverable_signed_execution(self.chain.chain_id, &wallet_address)
.await?,
"A recoverable execution for wallet {} retains signed transaction bytes; refusing to reuse its nonce without explicit recovery",
self.wallet_address
);
let Some(intent) = database
.get_active_execution_intent(self.chain.chain_id, &wallet_address)
.await?
else {View on GitHub (pinned to 18893faf8b)