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 checks that the strategy_id persisted on the execution intent row equals the strategy_id of the restored order. A mismatch means the durable swap intent and the cached order belong to different trading strategies, so the client refuses to rebuild the SwapPlan. This prevents a persisted swap from being attributed to, or executed on behalf of, the wrong strategy.
Solutions
- Restore the original strategy_id configuration so the restored order's strategy matches the persisted intent.
- Let the pending swap resolve before changing strategy assignments/renames, or manually finalize/cancel the intent in the durable store.
- Use a per-strategy (or per-deployment) durable store so intents are not mixed across strategy layouts.
- If the row is genuinely stale/corrupt, mark or delete the active intent so reconciliation can proceed.
Defensive patterns
Strategy: validation
Validate before calling
if intent.strategy_id.as_deref() != Some(order.strategy_id().as_str()) {
eprintln!("strategy mismatch between persisted intent and restored order; resolve pending swaps before renaming strategies");
} Type guard
fn strategy_matches(intent: &ExecutionIntentRow, order: &OrderAny) -> bool {
intent.strategy_id.as_deref() == Some(order.strategy_id().as_str())
} Prevention
- Avoid renaming StrategyId while swaps are pending in the durable store
- Scope durable stores per strategy or per deployment
- Restore orders from the same snapshot that produced the intents
- Check for NULL strategy_id on legacy rows before reconnecting
When it happens
Trigger: reconcile_unresolved_execution (from connect) or build_execution_verification_migration finds an active ExecutionIntentRow whose intent.strategy_id is None or differs from order.strategy_id() of the restored order. Occurs when strategy IDs were renamed/reassigned between runs, or orders were restored from a snapshot with different strategy assignments.
Common situations: Renaming a StrategyId in the trading config while a swap intent is still pending in the durable store; reassigning instruments/orders to a different strategy; sharing one database across deployments with different strategy layouts; old persisted rows predating strategy-id tracking (NULL column).
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Persisted swap account does not match execution client…
- Persisted swap trader does not match restored order
- Execution intent has no persisted signed transaction bytes
- No durable store configured for execution reconciliation
- Persisted pool does not match restored pool
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/32115d5460dbed23.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/blockchain/src/execution/client.rs:1053
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 18893faf8b)