FuelLabs/fuel-core · critical

Registry root mismatch. registry root after decompression

Error message

Registry root mismatch. registry root after decompression: {:?}, registry root after compression: {:?}

What it means

With fault-proving enabled, decompression recomputes the registry root over the decompression-side registry and compares it with registry_root stored in the compressed block header (V1); any difference aborts with 'Registry root mismatch…' (crates/compression/src/decompress.rs:126). This is the fault-proving integrity check firing: the registry content used to decompress differs from the content used to compress — e.g. pruned/missing registrations, divergent temporal registry retention, or the wrong DB. It signals real state divergence, not a transient failure.

Solutions

  1. Restore the registry state as of the block's height so every referenced registration is present.
  2. Align temporal_registry_retention (crates/compression/src/config.rs) between producing and verifying setups.
  3. If entries legitimately expired, re-register and re-compress the block rather than decompressing against stale registry state.
  4. Treat occurrences as a verification failure: capture the block and registry roots for forensics instead of retrying.
Defensive patterns

Strategy: try-catch

Try / catch

match compressed_block.decompress(&mut db).await {
    Err(e) if e.to_string().contains("Registry root mismatch") => {
        // integrity failure: halt verification, preserve the block + registry roots for forensics;
        // retrying against the same registry state will fail again
        return Err(e.context("registry divergence during fault proving"));
    }
    r => r?,
}

Prevention

When it happens

Trigger: Decompressing a V1 compressed block against a registry DB whose contents differ from compression time: registrations pruned after temporal_registry_retention elapsed, registrations at different indices, or an entirely different registry state.

Common situations: Replaying or fault-proving old blocks after registry entries expired; verifier pointed at a different snapshot than the producer; partial registry import; temporal_registry_retention configured differently between compressor and verifier.

Related errors


AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16). Data as JSON: /api/errors/844a560a397859ad. Report an issue: GitHub.

Appendix: source

Thrown at crates/compression/src/decompress.rs:126

            #[allow(clippy::arithmetic_side_effects)]
            u16::try_from(transaction_count - 1)?,
        );
    } else {
        anyhow::bail!("Last transaction is not a mint");
    }

    #[cfg(feature = "fault-proving")]
    {
        match block {
            VersionedCompressedBlock::V0(_) => {}
            VersionedCompressedBlock::V1(ref block) => {
                let registry_root_after_decompression = ctx
                    .db
                    .registry_root()
                    .map_err(|e| anyhow::anyhow!("Failed to get registry root: {}", e))?;
                let registry_root_after_compression = block.header.registry_root;
                if registry_root_after_decompression != registry_root_after_compression {
                    anyhow::bail!(
                        "Registry root mismatch. registry root after decompression: {:?}, registry root after compression: {:?}",
                        registry_root_after_decompression,
                        registry_root_after_compression
                    );
                }
            }
        }
    }

    Ok(PartialFuelBlock {
        header: block.partial_block_header(),
        transactions,
    })
}

pub struct DecompressCtx<D> {
    pub config: Config,
    /// Timestamp of the block being decompressed

View on GitHub (pinned to b9d4d170da)