linera-io/linera-protocol · critical · ProofError
receipts root mismatch: computed {receipts_root}, header say
Error message
receipts root mismatch: computed {receipts_root}, header says {}. Receipt encoding may be incorrect. What it means
A permanent integrity check: the receipts trie rebuilt locally from the RPC's receipts must root exactly at block.header.receipts_root. A mismatch means the canonical EIP-2718 re-encoding of receipts is wrong for at least one receipt in the block (e.g. transaction-type envelope handling, OP deposit type 0x7e) or the RPC returned altered receipts. The generated proof would not verify on-chain, so generation aborts.
Source
Thrown at linera-bridge/src/proof/gen.rs:176
.collect();
// 5. Build receipt trie and generate proof
let receipt_rlp = canonical_receipts
.iter()
.find(|(idx, _)| *idx == tx_index)
.map(|(_, rlp)| rlp.clone())
.ok_or_else(|| {
ProofError::Permanent(anyhow::anyhow!(
"tx_index {tx_index} not found in block receipts"
))
})?;
let (receipts_root, proof_nodes) =
crate::proof::build_receipt_proof(&canonical_receipts, tx_index);
// Sanity check: computed receipts root matches block header
if receipts_root != block.header.inner.receipts_root {
return Err(ProofError::Permanent(anyhow::anyhow!(
"receipts root mismatch: computed {receipts_root}, \
header says {}. Receipt encoding may be incorrect.",
block.header.inner.receipts_root
)));
}
// Find all DepositInitiated log indices from the canonical receipt
let logs =
crate::proof::decode_receipt_logs(&receipt_rlp).map_err(ProofError::Permanent)?;
let log_indices = crate::proof::find_deposit_log_indices(&logs);
if log_indices.is_empty() {
return Err(ProofError::Permanent(anyhow::anyhow!(
"no DepositInitiated event found in receipt for tx {tx_hash}"
)));
}
Ok(DepositProof {
block_header_rlp,View on GitHub (pinned to 6c226ddcb3)
Solutions
- Try a different RPC provider to rule out receipt tampering/normalization
- Check that the chain matches the client's network type (Optimism/Base with 0x7e deposit receipts)
- Compare the failing block's receipts against a reference node and identify which receipt type mis-encodes
- Update alloy/op-alloy and linera-bridge — receipt encoding fixes land there
Defensive patterns
Strategy: fallback
Try / catch
Err(ProofError::Permanent(e)) if e.to_string().contains("receipts root mismatch") => {
// encoding integrity failure: fall back to another provider to rule out receipt tampering;
// if reproducible, halt processing for this chain and escalate — proofs would not verify
} Prevention
- Update linera-bridge/alloy/op-alloy when new transaction types appear on the chain
- Run the crate's fixture tests (e.g. Base mainnet receipt proof) after dependency upgrades
- Treat this as a stop-the-line integrity failure, never a retryable hiccup
When it happens
Trigger: A block containing a transaction type whose receipt envelope is encoded differently than this crate's OpReceiptEnvelope path expects; RPC providers returning receipts with adjusted fields; alloy/op-alloy version drift in encoded_2718 behavior.
Common situations: New or unusual transaction types landing on the chain after this code was written; upgraded RPC backends normalizing receipts; running against a non-OP chain while the client assumes Optimism receipt types.
Related errors
- header RLP hash mismatch: computed {computed_hash}, expected
- tx_index {tx_index} not found in block receipts
- block receipts not found for block {block_hash}
- no DepositInitiated event found in receipt for tx {tx_hash}
- invalid tx hash: {}
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/3a650d5d2251d7bd.
Report an issue: GitHub.