nautechsystems/nautilus_trader · error
Persisted transaction hash {} does not match signed transact
Error message
Persisted transaction hash {} does not match signed transaction hash {} What it means
validate_signed_transaction decodes the persisted raw transaction and compares its computed keccak hash against the hash stored in the SignedTransactionIntent. A mismatch means the persisted bytes do not correspond to the intent record — the stored transaction is not the one that was authorized, so authentication fails.
Source
Thrown at crates/adapters/blockchain/src/execution/transaction.rs:245
chain_id: tx.chain_id,
nonce: tx.nonce,
to,
value: tx.value,
input: tx.input.clone(),
gas_limit: tx.gas_limit,
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!(View on GitHub (pinned to 18893faf8b)
Solutions
- Recompute the keccak hash of the raw bytes and compare with intent.hash to confirm the mismatch on both sides
- Re-persist the correct signed transaction matching intent.hash, or update the intent to reference the actual signed tx
- Check for a replaced/cancelled transaction (same nonce, different hash) and reconcile with the nonce manager
- Verify no storage corruption — compare the blob against any secondary checksum or re-derive from the tx signing payload
Example fix
// before
validate_signed_transaction(&stored_raw, &intent)?; // stored_raw from wrong row
// after
let decoded = decode_signed_transaction(&stored_raw)?;
if decoded.hash != intent.hash {
// re-persist the signed tx that matches intent.hash before validating
}
validate_signed_transaction(&stored_raw, &intent)?; Defensive patterns
Strategy: validation
Validate before calling
fn hashes_match(raw: &[u8], intent: &SignedTransactionIntent) -> anyhow::Result<bool> {
let decoded = decode_signed_transaction(raw)?;
Ok(decoded.hash == intent.hash)
} Type guard
fn matches_intent(decoded: &DecodedSignedTransaction, intent: &SignedTransactionIntent) -> bool {
decoded.hash == intent.hash
} Try / catch
match validate_signed_transaction(&raw, &intent) {
Ok(()) => (),
Err(e) if e.to_string().contains("does not match signed transaction hash") => {
// reconcile intent vs stored tx (replaced tx? wrong row?) before retrying
}
Err(e) => return Err(e),
} Prevention
- Write the intent hash and raw bytes atomically in the same transaction
- Verify hash == intent.hash immediately after persisting the signed transaction
- Handle transaction replacement (same nonce) by updating the intent, not just the blob
- Log both hashes on mismatch for fast forensics
When it happens
Trigger: Calling validate_signed_transaction (or authenticate_payload_identity_with_signer) where decode_signed_transaction(raw).hash != intent.hash — e.g. a different raw transaction was persisted than the intent, bytes were altered after persisting, or the intent record points at the wrong row/blob.
Common situations: Race where a transaction is replaced/re-signed but the intent hash was not updated; DB row pointing at the wrong blob; blob corruption altering bytes without changing the stored intent hash; copy-paste between environments.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Finalized checkpoint ledger conflicts with the trusted chain
- Verified transaction fields differ from the authenticated si
- Verified inclusion header {} does not match receipt hash {}
- Retained signed intent {} has no authenticated current paylo
- Signed transaction nonce {} does not match persisted nonce {
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5517dd708d6429a0.
Report an issue: GitHub.