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
- Compare intent.durable_signer and intent.signer for the failing intent row; confirm which one is stale
- 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
- If the row is stale/corrupt, delete or re-persist the intent through the normal write path so durable_signer and signer agree
- 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
- Derive durable_signer and signer from a single wallet config value so they cannot diverge
- Invalidate and re-create persisted intents on wallet rotation instead of editing rows
- Validate the signer pair at intent write time, not only at replay time
- Watch for environments where DB rows are copied across wallets/environments
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
- Signed transaction signer {} does not match configured walle
- Execution intent {} signed transaction {} failed authenticat
- Canonical signer-nonce transaction {} has no authenticated r
- Persisted intent chain ID {} does not match configured chain
- Signed transaction chain ID {} does not match configured cha
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ddd5bdd2f1352c9b.
Report an issue: GitHub.