nautechsystems/nautilus_trader · error

Finality verification disagreed with the receipt or finalize

Error message

Finality verification disagreed with the receipt or finalized header

What it means

As a final consistency pass, the client re-verifies both the receipt's canonical block and the finalized header. The check requires the re-read canonical hash to equal the receipt's block hash AND the re-read finalized header to equal the previously determined one. Any disagreement means the verification source changed its answer between reads or the receipt/header is inconsistent.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:3494

            ));
            finalized_headers.extend(ancestry.iter().copied());
        }
        anyhow::ensure!(
            ancestry_cursor == finalized,
            "Finalized header conflicts with its verified ancestry"
        );

        let canonical_again_verification = required_verification(
            self.verification.verify_block(receipt.block_number).await,
            "finality inclusion header reread",
        )?;
        let canonical_again = canonical_again_verification.value;
        let finalized_again_verification = required_verification(
            self.verification.verify_block(finalized.number).await,
            "finalized header reread",
        )?;
        let finalized_again = finalized_again_verification.value;
        anyhow::ensure!(
            canonical_again.hash == receipt.block_hash && finalized_again == finalized,
            "Finality verification disagreed with the receipt or finalized header"
        );
        decisions.extend([
            verification_decision(
                &finalized_verification,
                Some(finalized.number),
                Some(finalized.number),
            ),
            verification_decision(
                &canonical_again_verification,
                Some(receipt.block_number),
                Some(receipt.block_number),
            ),
            verification_decision(
                &finalized_again_verification,
                Some(finalized.number),
                Some(finalized.number),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pin all verification calls to a single consistent RPC node (disable mixed-node load balancing).
  2. Log both verification results and retry after the chain stabilizes.
  3. If a reorg is confirmed, restart finality verification from the checkpoint with refreshed state.

Example fix

// before: two calls may hit different fork nodes
let canonical_again = self.verification.verify_block(receipt.block_number).await?;
// after: pinned, consistent source
let canonical_again = self.pinned_verification().verify_block(receipt.block_number).await?;
Defensive patterns

Strategy: retry

Validate before calling

let c1 = verification.verify_block(receipt.block_number).await?;
let c2 = verification.verify_block(receipt.block_number).await?;
anyhow::ensure!(c1 == c2, "verification source unstable between reads");

Try / catch

match result {
    Err(e) if e.to_string().contains("disagreed with the receipt") => {
        backoff_then_retry_with_pinned_node()
    }
    other => other,
}

Prevention

When it happens

Trigger: During finality verification when `verify_block(receipt.block_number).hash != receipt.block_hash` or `verify_block(finalized.number) != finalized` — e.g. a reorg landed between the two verification passes, or a load-balanced RPC pool returned different-chain nodes.

Common situations: Unstable reorg churn at the canonical head; RPC endpoints behind a load balancer serving different backends/forks; provider bug returning inconsistent headers across calls.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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