nautechsystems/nautilus_trader · error · anyhow::Error
Persisted swap trader does not match restored order
Error message
Persisted swap trader does not match restored order
What it means
restore_swap_plan (crates/adapters/blockchain/src/execution/client.rs:845) verifies the persisted intent's trader_id equals the trader of the order restored under its client order id. A mismatch means the durable swap record belongs to a different trader than the live order - the client refuses to reconcile because completing it would attribute executions to the wrong account holder. The check guarantees trader attribution of emitted fills matches the persisted intent exactly.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:845
.try_order_owned(&client_order_id)
.with_context(|| {
format!(
"Cannot reconcile swap intent {} because order {client_order_id} is not restored",
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"))?,View on GitHub (pinned to 2114cf6f76)
Solutions
- Check the intent row's trader_id versus the current trader configuration and the restored order's trader.
- Resolve the orphaned intent on-chain (verify the transaction outcome) and mark it resolved so reconciliation no longer picks it up.
- When changing trader configuration, drain or clear active intents first.
- Scope intents per trader in the database to avoid cross-trader collisions.
Defensive patterns
Strategy: try-catch
Validate before calling
-- Pre-flight: intents recorded under a trader other than the one you will boot
SELECT id, trader_id, status
FROM execution_intent
WHERE status IN ('prepared', 'signed', 'submitted'); Type guard
fn is_trader_mismatch(e: &anyhow::Error) -> bool {
e.to_string().contains("Persisted swap trader does not match restored order")
} Try / catch
if let Err(e) = client.connect().await {
if is_trader_mismatch(&e) {
// attribution conflict: boot the trader that owns the intent, or resolve it first
log::error!("swap intent belongs to a different trader: {e}");
}
return Err(e);
} Prevention
- Drain active intents before changing trader configuration.
- Give each trader its own durable store, or verify no foreign intents exist at boot.
- Keep trader_id constant for the lifetime of any intent it creates.
When it happens
Trigger: Trader configuration changed between the run that persisted the intent and the restarted run reconciling it; an order cache restored under a different trader_id while the old intent row remains active; intents written by a prior deployment under another trader account.
Common situations: Re-keying a deployment from a test trader to a production trader without clearing durable intents; multi-trader setups sharing one Postgres store.
Related errors
- Persisted swap strategy 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/18721d225c480b12.
Report an issue: GitHub.