nautechsystems/nautilus_trader · error · anyhow::Error
Persisted pool does not match restored pool
Error message
Persisted pool {pool_address} does not match restored pool {} What it means
After parsing the persisted pool_address, restore_swap_plan resolves the pool for the intent's instrument via resolve_pool and compares its on-chain address with the persisted one. If the registered/restored pool for that instrument has a different address than what the intent was prepared against, the client aborts reconciliation. This guarantees the swap is replayed against exactly the pool it was originally created for, guarding against instrument remapping to a different pool contract.
Solutions
- Restore the original pool/instrument registration so resolve_pool returns the pool address stored in the intent.
- Resolve or cancel the pending intent before changing pool configuration, then re-issue the trade.
- Verify chain_id and network configuration match the environment where the intent was persisted.
- Inspect the intent row and current instrument definition to confirm which is stale, and fix the stale side.
Defensive patterns
Strategy: validation
Validate before calling
let pool = client.resolve_pool(&instrument_id)?;
if pool.address != intent_pool_address {
eprintln!("pool for {instrument_id} changed since intent was written; restore original registration or cancel the intent");
} Type guard
fn pool_matches(pool: &Pool, persisted: Address) -> bool {
pool.address == persisted
} Prevention
- Do not change pool/instrument definitions while swap intents are pending
- Pin chain_id and contract addresses per environment; never share DBs across networks
- Record and compare factory/pool addresses when migrating deployments
- Resolve pending intents before re-registering instruments
When it happens
Trigger: reconcile_unresolved_execution or build_execution_verification_migration calls restore_swap_plan on an intent whose persisted pool_address differs from the address of the pool resolved for intent.instrument_id. Occurs when the instrument's pool registration changed between persisting and restoring (different DEX/pool configured), or the intent belongs to a different chain/fork with a same-instrument but different pool.
Common situations: Changing the pool/instrument definition (e.g. new pool deployment, different fee tier) while an old swap intent was still pending; pointing the node at a different chain or forked network with different contract addresses; loading another environment's database.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Persisted swap intent has no input amount
- Persisted swap intent has no pool address
- Restored pool references factory , expected registered…
- Execution intent has no persisted signed transaction bytes
- Finalized transaction
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f4e62543dbb267fb.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/blockchain/src/execution/client.rs:1069
"Persisted swap trader does not match restored order"
);
anyhow::ensure!(
intent.strategy_id.as_deref() == Some(order.strategy_id().as_str()),
"Persisted swap strategy does not match restored order"
);
anyhow::ensure!(
intent.account_id.as_deref() == Some(self.core.account_id.as_str()),
"Persisted swap account does not match execution client account"
);
let pool = self.resolve_pool(&instrument_id)?;
let pool_address = Address::from_str(
intent
.pool_address
.as_deref()
.ok_or_else(|| anyhow::anyhow!("Persisted swap intent has no pool address"))?,
)?;
anyhow::ensure!(
pool.address == pool_address,
"Persisted pool {pool_address} does not match restored pool {}",
pool.address
);
let amount_in = U256::from_str(
intent
.amount_in
.as_deref()
.ok_or_else(|| anyhow::anyhow!("Persisted swap intent has no input amount"))?,
)?;
let fee = U24::try_from(
pool.fee
.ok_or_else(|| anyhow::anyhow!("Restored pool {instrument_id} has no fee"))?,
)?;
let quote_token = pool.get_quote_token();
let quote_currency = Currency::new_checked(
"e_token.symbol,
quote_token.decimals,View on GitHub (pinned to 18893faf8b)