{"record":{"id":"ddd5bdd2f1352c9b","repo":"nautechsystems/nautilus_trader","slug":"persisted-transaction-signer-does-not-match-con","errorCode":null,"errorMessage":"Persisted transaction signer {} does not match configured wallet {}","messagePattern":"Persisted transaction signer (.+?) does not match configured wallet (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/transaction.rs","lineNumber":251,"sourceCode":"        max_fee_per_gas: tx.max_fee_per_gas,\n        max_priority_fee_per_gas: tx.max_priority_fee_per_gas,\n    })\n}\n\n/// Authenticates one complete signed EIP-1559 call against its durable intent and policy.\npub(super) fn validate_signed_transaction(\n    raw_transaction: &[u8],\n    intent: &SignedTransactionIntent,\n) -> anyhow::Result<()> {\n    let tx = decode_signed_transaction(raw_transaction)?;\n\n    anyhow::ensure!(\n        tx.hash == intent.hash,\n        \"Persisted transaction hash {} does not match signed transaction hash {}\",\n        intent.hash,\n        tx.hash\n    );\n    anyhow::ensure!(\n        intent.durable_signer == intent.signer,\n        \"Persisted transaction signer {} does not match configured wallet {}\",\n        intent.durable_signer,\n        intent.signer\n    );\n    anyhow::ensure!(\n        tx.signer == intent.signer,\n        \"Signed transaction signer {} does not match configured wallet {}\",\n        tx.signer,\n        intent.signer\n    );\n    anyhow::ensure!(\n        intent.intent_chain_id == intent.chain_id,\n        \"Persisted intent chain ID {} does not match configured chain ID {}\",\n        intent.intent_chain_id,\n        intent.chain_id\n    );\n    anyhow::ensure!(","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/transaction.rs#L233-L269","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (row drifted from configured wallet)\nlet intent = SignedTransactionIntent { durable_signer: old_wallet, signer: configured_wallet, .. };\nvalidate_signed_transaction(&raw, &intent)?; // ensure! fails\n// after: re-persist the intent under the configured wallet\nlet intent = SignedTransactionIntent { durable_signer: configured_wallet, signer: configured_wallet, .. };\nvalidate_signed_transaction(&raw, &intent)?;","handlingStrategy":"validation","validationCode":"fn signer_matches(intent: &SignedTransactionIntent) -> bool {\n    intent.durable_signer == intent.signer\n}\nif !signer_matches(&intent) {\n    // reject or re-persist the intent before calling authenticate_payload_identity_with_signer\n    return Err(anyhow::anyhow!(\"intent durable_signer != configured signer\"));\n}","typeGuard":"fn is_intent_for_wallet(intent: &SignedTransactionIntent, wallet: Address) -> bool {\n    intent.signer == wallet && intent.durable_signer == wallet\n}","tryCatchPattern":"match authenticate_payload_identity_with_signer(&raw, &intent) {\n    Ok(()) => { /* proceed */ }\n    Err(e) if e.to_string().contains(\"does not match configured wallet\") => {\n        // wallet drift: invalidate the intent and re-create it under the configured wallet\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["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"],"tags":["blockchain","transaction-signing","authentication","chain-adapter"],"backgroundTag":"invalid-argument-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}