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

  1. Recompute the keccak hash of the raw bytes and compare with intent.hash to confirm the mismatch on both sides
  2. Re-persist the correct signed transaction matching intent.hash, or update the intent to reference the actual signed tx
  3. Check for a replaced/cancelled transaction (same nonce, different hash) and reconcile with the nonce manager
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/5517dd708d6429a0. Report an issue: GitHub.