nautechsystems/nautilus_trader · error · anyhow::Error

Persisted swap account does not match execution client…

Error message

Persisted swap account does not match execution client account

What it means

restore_swap_plan verifies that the account_id persisted on the execution intent matches the account_id of this execution client (self.core.account_id). A mismatch means the durable swap intent was written by a different execution client account (e.g. another wallet or venue account), so reconciliation refuses to restore and re-drive the swap. This stops swaps belonging to one account from being executed by another.

Solutions

  1. Configure the execution client with the same account_id that persisted the intents (revert wallet/account changes or use the original database).
  2. Separate durable stores per account so intents are never shared across accounts.
  3. Resolve or clear the pending intent in the durable store before switching accounts.
  4. Verify cache/database wiring so the node connects to the store belonging to the configured account.

Example fix

// before
account_id = "BLOCKCHAIN-0xNewWallet"
// after (account that wrote the intents)
account_id = "BLOCKCHAIN-0xOriginalWallet"
Defensive patterns

Strategy: validation

Validate before calling

if intent.account_id.as_deref() != Some(exec_client_account_id.as_str()) {
    eprintln!("persisted intent belongs to a different account; align account_id config or use the original database");
}

Type guard

fn account_matches(intent: &ExecutionIntentRow, client_account_id: &AccountId) -> bool {
    intent.account_id.as_deref() == Some(client_account_id.as_str())
}

Prevention

When it happens

Trigger: reconcile_unresolved_execution or build_execution_verification_migration restores an ExecutionIntentRow whose intent.account_id is None or differs from self.core.account_id during restore_swap_plan. Happens when the execution client's account (wallet/venue account id) changed between runs, or the durable store contains intents from another account.

Common situations: Rotating wallet or changing account_id config while intents were pending; pointing one node at another account's database; running multiple execution clients (different accounts) against a shared durable store; old rows with NULL account_id.

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/777df2cfb4e1d9da. Report an issue: GitHub.

Appendix: source

Thrown at crates/adapters/blockchain/src/execution/client.rs:1057

            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 {}",
            pool.address
        );
        let amount_in = U256::from_str(
            intent

View on GitHub (pinned to 18893faf8b)