FuelLabs/fuel-core · error · StorageError
The count of leaves - messages is zero
Error message
The count of leaves - messages is zero
What it means
block_history_proof computes the leaf index as message_merkle_metadata.version() - 1 (the count of message leaves recorded before this block). checked_sub(1) fails when version() == 0, meaning the message block's merkle metadata records zero leaves — there are no messages to prove at or before that block. Requesting an inclusion proof for a message whose block contains no message leaves is therefore invalid.
Source
Thrown at crates/fuel-core/src/database/block.rs:119
let message_merkle_metadata = self
.storage::<FuelBlockMerkleMetadata>()
.get(&DenseMetadataKey::Primary(*message_block_height))?
.ok_or(not_found!(FuelBlockMerkleMetadata))?;
let commit_merkle_metadata = self
.storage::<FuelBlockMerkleMetadata>()
.get(&DenseMetadataKey::Primary(*commit_block_height))?
.ok_or(not_found!(FuelBlockMerkleMetadata))?;
let storage = self;
let tree: MerkleTree<FuelBlockMerkleData, _> =
MerkleTree::load(storage, commit_merkle_metadata.version())
.map_err(|err| StorageError::Other(anyhow::anyhow!(err)))?;
let proof_index = message_merkle_metadata
.version()
.checked_sub(1)
.ok_or(anyhow::anyhow!("The count of leaves - messages is zero"))?;
let (_, proof_set) = tree
.prove(proof_index)
.map_err(|err| StorageError::Other(anyhow::anyhow!(err)))?;
Ok(MerkleProof {
proof_set,
proof_index,
})
}
}
#[allow(clippy::arithmetic_side_effects)]
#[cfg(test)]
mod tests {
use super::*;
use crate::database::Database;
use fuel_core_storage::{
StorageMutate,View on GitHub (pinned to b9d4d170da)
Solutions
- Verify the message is actually contained in message_block_height (check the message's committed height) before requesting the proof.
- If heights come from external metadata, refresh them after re-orgs or DA finality changes.
- Treat this error as 'no such message proof at this height' and surface an invalid-request error to callers.
Defensive patterns
Strategy: validation
Validate before calling
// Before proving, confirm the message block actually contains message leaves.
let meta = view
.storage::<FuelBlockMerkleMetadata>()
.get(&DenseMetadataKey::Primary(*message_block_height))?;
if meta.map(|m| *m.value().version() == 0).unwrap_or(true) {
anyhow::bail!("no message leaves at block {}; wrong message height?", message_block_height);
}
let proof = view.block_history_proof(message_block_height, commit_block_height)?; Try / catch
match view.block_history_proof(&msg_h, &commit_h) {
Ok(p) => Ok(p),
Err(e) if e.to_string().contains("leaves - messages is zero") => {
// the block has no messages: the requested message cannot be proven there
Err(not_found!(FuelBlockMerkleMetadata))
}
Err(e) => Err(e),
} Prevention
- Derive message_block_height from the message's own committed status, not from external guesses.
- Re-validate heights after re-orgs before requesting proofs.
- Treat a zero-leaf block as 'message not found' at the API layer.
When it happens
Trigger: Requesting a message proof where the block identified by message_block_height has FuelBlockMerkleMetadata version 0 (no messages committed up to that point) — e.g., proving against a wrong block height or a block that never contained the message.
Common situations: Bridge/relayer code deriving the message block height incorrectly and landing on an empty block; querying proofs for messages not yet committed; chain re-orgs leaving stale message-height references.
Related errors
- The `message_block_height` is higher than `commit_block_heig
- message da_height cannot be greater than genesis da block he
- Could not convert proof_set entry to Bytes32: {}
- {error}
- The block height subscription channel was closed: {:?}
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/655c3aac29e6c8a9.
Report an issue: GitHub.