{"record":{"id":"5e491ed0cd32b981","repo":"nautechsystems/nautilus_trader","slug":"signed-transaction-signer-does-not-match-config","errorCode":null,"errorMessage":"Signed transaction signer {} does not match configured wallet {}","messagePattern":"Signed transaction signer (.+?) does not match configured wallet (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/transaction.rs","lineNumber":257,"sourceCode":"pub(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!(\n        intent.row_chain_id == intent.chain_id,\n        \"Persisted transaction row chain ID {} does not match configured chain ID {}\",\n        intent.row_chain_id,\n        intent.chain_id\n    );\n","sourceCodeStart":239,"sourceCodeEnd":275,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/transaction.rs#L239-L275","documentation":"In `validate_signed_transaction` (crates/adapters/blockchain/src/execution/transaction.rs:257), after decoding the persisted EIP-1559 envelope, the signer address recovered from the signature is compared to the configured wallet (`intent.signer`). The library refuses to treat a signed transaction as authorized when it was actually signed by a different key — this is a defense against replaying transactions signed by an unauthorized key under someone else's intent.","triggerScenarios":"Passing raw signed-transaction bytes whose ECDSA signature recovers to an address different from `intent.signer` into `authenticate_payload_identity_with_signer` / `validate_signed_transaction`. Also occurs when the wallet changed between persist and replay, or the wrong raw bytes are paired with the intent.","commonSituations":"Configured wallet/key rotation without re-signing persisted transactions; passing a different transaction's raw bytes to the wrong intent; using a test/dev key in one environment and a production key in another; multisig or relayer signing with a hot key that differs from the configured address.","solutions":["Recover the signer from the raw bytes and compare with intent.signer to confirm which key actually signed","Re-sign the transaction with the configured wallet's key and re-persist the intent/raw pair","Ensure the configured wallet (keystore, private key env var, provider account) is the same one used to produce the signature","Verify you are passing the correct raw transaction bytes for this intent (hash check precedes this check, so bytes likely belong to another intent)"],"exampleFix":"// before: signed with a different key\nlet signed = signer_b.sign_tx(tx).encoded_2718();\nvalidate_signed_transaction(&signed, &intent_for_signer_a)?; // ensure! fails\n// after: sign with the configured wallet\nlet signed = configured_wallet.sign_tx_sync_without_keystore256(tx).encoded_2718();\nvalidate_signed_transaction(&signed, &intent_for_signer_a)?;","handlingStrategy":"validation","validationCode":"let decoded = decode_signed_transaction(&raw)?;\nif decoded.signer != intent.signer {\n    return Err(anyhow::anyhow!(\"raw tx signed by {}, intent requires {}\", decoded.signer, intent.signer));\n}","typeGuard":"fn signed_by_configured_wallet(tx: &DecodedSignedTransaction, intent: &SignedTransactionIntent) -> bool {\n    tx.signer == intent.signer\n}","tryCatchPattern":"match authenticate_payload_identity_with_signer(&raw, &intent) {\n    Ok(()) => { /* proceed */ }\n    Err(e) if e.to_string().contains(\"Signed transaction signer\") => {\n        // wrong key: re-sign with the configured wallet before retrying\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always sign with the wallet resolved from the same config the intent was built from","Pair raw signed bytes with their intent atomically so bytes can't be matched to the wrong intent","Recover the signer address immediately after signing and assert it equals the configured wallet","Keep test/dev keys out of production signing paths"],"tags":["blockchain","transaction-signing","ecdsa","authentication"],"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"}