nautechsystems/nautilus_trader · error · anyhow::Error
Persisted swap strategy does not match restored order
Error message
Persisted swap strategy does not match restored order
What it means
restore_swap_plan (crates/adapters/blockchain/src/execution/client.rs:849) requires the persisted intent's strategy_id to match the strategy of the restored order named by its client order id. A mismatch means the durable swap record was spawned by a different strategy than the live order - reconciliation aborts so fills are never attributed to the wrong strategy. Strategy attribution flows into every emitted order event, hence the strict equality check.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:849
intent.id
)
})?;
let instrument_id = InstrumentId::from_str(
intent
.instrument_id
.as_deref()
.ok_or_else(|| anyhow::anyhow!("Persisted swap intent has no instrument ID"))?,
)?;
anyhow::ensure!(
order.instrument_id() == instrument_id,
"Persisted swap instrument {instrument_id} does not match restored order instrument {}",
order.instrument_id()
);
anyhow::ensure!(
intent.trader_id.as_deref() == Some(order.trader_id().as_str()),
"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 {}",View on GitHub (pinned to 2114cf6f76)
Solutions
- Compare the intent's strategy_id with the current strategy configuration and the restored order's strategy.
- Verify the on-chain outcome of the intent's transaction and mark the intent resolved to unblock reconciliation.
- Clear active intents before changing strategy identifiers.
- Keep strategy ids stable for the lifetime of any intent they create.
Defensive patterns
Strategy: try-catch
Validate before calling
-- Pre-flight: intents recorded under a strategy other than current config
SELECT id, strategy_id, status
FROM execution_intent
WHERE status IN ('prepared', 'signed', 'submitted'); Type guard
fn is_strategy_mismatch(e: &anyhow::Error) -> bool {
e.to_string().contains("Persisted swap strategy does not match restored order")
} Try / catch
if let Err(e) = client.connect().await {
if is_strategy_mismatch(&e) {
// strategy attribution conflict: resolve the stale intent before trading
log::error!("swap intent belongs to a different strategy: {e}");
}
return Err(e);
} Prevention
- Do not rename strategies while intents from the old strategy are active.
- Clear or complete active intents before reassigning strategy ids.
- Keep strategy_id stable for the lifetime of any intent it creates.
When it happens
Trigger: Strategy configuration changed across restarts while an intent persisted by the old strategy is still active; the order cache restored under a different strategy id; a client order id reused by a different strategy in a later session.
Common situations: Renaming strategies in config between runs; promoting a strategy id from paper to live trading with stale intents in the store.
Related errors
- Persisted swap trader does not match restored order
- Persisted swap account does not match execution client accou
- Persisted pool {pool_address} does not match restored pool {
- Persisted swap instrument {instrument_id} does not match res
- No durable store configured for execution reconciliation
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/32115d5460dbed23.
Report an issue: GitHub.