nautechsystems/nautilus_trader · error

Persisted transaction signer {} does not match configured wa

Error message

Persisted transaction signer {} does not match configured wallet {}

What it means

This error comes from the durable-transaction authentication path `validate_signed_transaction` in crates/adapters/blockchain/src/execution/transaction.rs. Before any persisted signed transaction is replayed, the library checks that the signer address stored in the durable intent (`durable_signer`) is identical to the wallet the intent was configured with (`signer`). If they differ, the persisted record was created by (or tampered/migrated to) a different wallet than the configured one, and replay is refused to prevent signing under an unexpected key.

Source

Thrown at crates/adapters/blockchain/src/execution/transaction.rs:251

        max_fee_per_gas: tx.max_fee_per_gas,
        max_priority_fee_per_gas: tx.max_priority_fee_per_gas,
    })
}

/// Authenticates one complete signed EIP-1559 call against its durable intent and policy.
pub(super) fn validate_signed_transaction(
    raw_transaction: &[u8],
    intent: &SignedTransactionIntent,
) -> anyhow::Result<()> {
    let tx = decode_signed_transaction(raw_transaction)?;

    anyhow::ensure!(
        tx.hash == intent.hash,
        "Persisted transaction hash {} does not match signed transaction hash {}",
        intent.hash,
        tx.hash
    );
    anyhow::ensure!(
        intent.durable_signer == intent.signer,
        "Persisted transaction signer {} does not match configured wallet {}",
        intent.durable_signer,
        intent.signer
    );
    anyhow::ensure!(
        tx.signer == intent.signer,
        "Signed transaction signer {} does not match configured wallet {}",
        tx.signer,
        intent.signer
    );
    anyhow::ensure!(
        intent.intent_chain_id == intent.chain_id,
        "Persisted intent chain ID {} does not match configured chain ID {}",
        intent.intent_chain_id,
        intent.chain_id
    );
    anyhow::ensure!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Compare intent.durable_signer and intent.signer for the failing intent row; confirm which one is stale
  2. If the configured wallet legitimately changed, invalidate/expire the persisted intent and re-create it (re-sign) under the new wallet rather than editing the row
  3. If the row is stale/corrupt, delete or re-persist the intent through the normal write path so durable_signer and signer agree
  4. Verify wallet configuration (env vars/keystore) so the configured signer matches the wallet used when the intent was persisted

Example fix

// before (row drifted from configured wallet)
let intent = SignedTransactionIntent { durable_signer: old_wallet, signer: configured_wallet, .. };
validate_signed_transaction(&raw, &intent)?; // ensure! fails
// after: re-persist the intent under the configured wallet
let intent = SignedTransactionIntent { durable_signer: configured_wallet, signer: configured_wallet, .. };
validate_signed_transaction(&raw, &intent)?;
Defensive patterns

Strategy: validation

Validate before calling

fn signer_matches(intent: &SignedTransactionIntent) -> bool {
    intent.durable_signer == intent.signer
}
if !signer_matches(&intent) {
    // reject or re-persist the intent before calling authenticate_payload_identity_with_signer
    return Err(anyhow::anyhow!("intent durable_signer != configured signer"));
}

Type guard

fn is_intent_for_wallet(intent: &SignedTransactionIntent, wallet: Address) -> bool {
    intent.signer == wallet && intent.durable_signer == wallet
}

Try / catch

match authenticate_payload_identity_with_signer(&raw, &intent) {
    Ok(()) => { /* proceed */ }
    Err(e) if e.to_string().contains("does not match configured wallet") => {
        // wallet drift: invalidate the intent and re-create it under the configured wallet
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling `authenticate_payload_identity_with_signer` (or tests invoking `validate_signed_transaction` directly) with a `SignedTransactionIntent` whose `durable_signer != intent.signer`. The transaction bytes themselves may be perfectly valid — the mismatch is purely between the persisted intent row and the configured wallet.

Common situations: Rotating or switching the configured wallet (e.g. changing a keystore/env-derived key or RPC account) while old persisted transaction intent rows still reference the previous signer; restoring database rows from another environment; a migration or manual DB edit that rewrote one of the two fields; misconfiguring the wallet address in config so it differs from what was used when the intent was persisted.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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