{"record":{"id":"7b5a14febba46c93","repo":"nautechsystems/nautilus_trader","slug":"signed-transaction-chain-id-does-not-match-conf","errorCode":null,"errorMessage":"Signed transaction chain ID {} does not match configured chain ID {}","messagePattern":"Signed transaction chain ID (.+?) does not match configured chain ID (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/transaction.rs","lineNumber":276,"sourceCode":"        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\n    anyhow::ensure!(\n        tx.chain_id == u64::from(intent.chain_id),\n        \"Signed transaction chain ID {} does not match configured chain ID {}\",\n        tx.chain_id,\n        intent.chain_id\n    );\n    anyhow::ensure!(\n        tx.nonce == intent.nonce,\n        \"Signed transaction nonce {} does not match persisted nonce {}\",\n        tx.nonce,\n        intent.nonce\n    );\n    anyhow::ensure!(\n        tx.to == intent.to,\n        \"Signed transaction destination {} does not match persisted destination {}\",\n        tx.to,\n        intent.to\n    );\n    anyhow::ensure!(","sourceCodeStart":258,"sourceCodeEnd":294,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/transaction.rs#L258-L294","documentation":"Finally, `validate_signed_transaction` compares the chain ID actually encoded in the signed EIP-1559 transaction (`tx.chain_id`, recovered from the raw bytes) against the configured chain ID. EIP-155 replay protection bakes the chain ID into the signature, so a mismatch means the transaction was signed for a different network and must never be broadcast by this adapter.","triggerScenarios":"Calling `authenticate_payload_identity_with_signer` / `validate_signed_transaction` with signed bytes whose embedded `tx.chain_id` differs from `u64::from(intent.chain_id)` — e.g. a transaction signed for mainnet while the adapter is configured for an L2, or vice versa.","commonSituations":"Signing with a wallet/provider bound to the wrong network; switching the adapter's chain configuration after signing; relaying transactions produced by another service configured for a different chain; EIP-155 signatures from testnet keys reaching a mainnet-configured pipeline.","solutions":["Re-sign the transaction with the wallet/provider bound to the configured chain so the EIP-155 chain ID matches","Align the adapter's configured chain_id with the chain the transaction was actually signed for, then re-persist intent + bytes together","Verify the signing provider/keystore is connected to the intended network before signing","Regenerate intent and signed bytes as an atomic pair whenever the chain configuration changes"],"exampleFix":"// before: tx signed for chain 1, adapter configured for 42161\nlet signed = provider_chain1.sign(tx).encoded_2718();\nvalidate_signed_transaction(&signed, &intent_chain_42161)?; // ensure! fails\n// after: sign against the configured chain\nlet signed = provider_arbitrum.sign(tx).encoded_2718(); // tx.chain_id = 42161\nvalidate_signed_transaction(&signed, &intent_chain_42161)?;","handlingStrategy":"validation","validationCode":"let decoded = decode_signed_transaction(&raw)?;\nif decoded.chain_id != Some(u64::from(intent.chain_id)) {\n    return Err(anyhow::anyhow!(\n        \"tx chain {:?} != configured chain {}\",\n        decoded.chain_id, intent.chain_id\n    ));\n}","typeGuard":"fn signed_for_configured_chain(tx: &DecodedSignedTransaction, intent: &SignedTransactionIntent) -> bool {\n    tx.chain_id == Some(u64::from(intent.chain_id))\n}","tryCatchPattern":"match authenticate_payload_identity_with_signer(&raw, &intent) {\n    Ok(()) => { /* proceed */ }\n    Err(e) if e.to_string().contains(\"Signed transaction chain ID\") => {\n        // EIP-155 mismatch: re-sign on the configured chain; do not broadcast\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Sign only through a provider/wallet bound to the configured chain","Assert the signing provider's get_chain_id() matches config before every signing batch","Regenerate intent and signed bytes together whenever chain configuration changes","Never relay transactions signed by external services without re-checking their embedded chain ID"],"tags":["blockchain","chain-id","replay-protection","transaction-signing"],"backgroundTag":"invalid-config-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"}