{"record":{"id":"655c3aac29e6c8a9","repo":"FuelLabs/fuel-core","slug":"the-count-of-leaves-messages-is-zero","errorCode":null,"errorMessage":"The count of leaves - messages is zero","messagePattern":"The count of leaves - messages is zero","errorType":"validation","errorClass":"StorageError","httpStatus":null,"severity":"error","filePath":"crates/fuel-core/src/database/block.rs","lineNumber":119,"sourceCode":"        let message_merkle_metadata = self\n            .storage::<FuelBlockMerkleMetadata>()\n            .get(&DenseMetadataKey::Primary(*message_block_height))?\n            .ok_or(not_found!(FuelBlockMerkleMetadata))?;\n\n        let commit_merkle_metadata = self\n            .storage::<FuelBlockMerkleMetadata>()\n            .get(&DenseMetadataKey::Primary(*commit_block_height))?\n            .ok_or(not_found!(FuelBlockMerkleMetadata))?;\n\n        let storage = self;\n        let tree: MerkleTree<FuelBlockMerkleData, _> =\n            MerkleTree::load(storage, commit_merkle_metadata.version())\n                .map_err(|err| StorageError::Other(anyhow::anyhow!(err)))?;\n\n        let proof_index = message_merkle_metadata\n            .version()\n            .checked_sub(1)\n            .ok_or(anyhow::anyhow!(\"The count of leaves - messages is zero\"))?;\n        let (_, proof_set) = tree\n            .prove(proof_index)\n            .map_err(|err| StorageError::Other(anyhow::anyhow!(err)))?;\n\n        Ok(MerkleProof {\n            proof_set,\n            proof_index,\n        })\n    }\n}\n\n#[allow(clippy::arithmetic_side_effects)]\n#[cfg(test)]\nmod tests {\n    use super::*;\n    use crate::database::Database;\n    use fuel_core_storage::{\n        StorageMutate,","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/fuel-core/src/database/block.rs#L101-L137","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Before proving, confirm the message block actually contains message leaves.\nlet meta = view\n    .storage::<FuelBlockMerkleMetadata>()\n    .get(&DenseMetadataKey::Primary(*message_block_height))?;\nif meta.map(|m| *m.value().version() == 0).unwrap_or(true) {\n    anyhow::bail!(\"no message leaves at block {}; wrong message height?\", message_block_height);\n}\nlet proof = view.block_history_proof(message_block_height, commit_block_height)?;","typeGuard":null,"tryCatchPattern":"match view.block_history_proof(&msg_h, &commit_h) {\n    Ok(p) => Ok(p),\n    Err(e) if e.to_string().contains(\"leaves - messages is zero\") => {\n        // the block has no messages: the requested message cannot be proven there\n        Err(not_found!(FuelBlockMerkleMetadata))\n    }\n    Err(e) => Err(e),\n}","preventionTips":["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."],"tags":["merkle-proof","messages","validation","graphql","rust"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}