{"record":{"id":"3314da905178a42f","repo":"FuelLabs/fuel-core","slug":"missing-protobuf-header","errorCode":null,"errorMessage":"Missing protobuf header","messagePattern":"Missing protobuf header","errorType":"exception","errorClass":"Error::Serialization","httpStatus":null,"severity":"error","filePath":"crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs","lineNumber":512,"sourceCode":"            ))\n        }\n    }?;\n\n    Ok(receipt)\n}\n\npub fn fuel_block_from_protobuf(\n    proto_block: ProtoBlock,\n) -> crate::result::Result<(FuelBlock, Vec<Vec<FuelReceipt>>)> {\n    let versioned_block = proto_block\n        .versioned_block\n        .ok_or_else(|| anyhow::anyhow!(\"Missing protobuf versioned_block\"))\n        .map_err(Error::Serialization)?;\n    let (partial_header, event_inbox_root, txs, receipts) = match versioned_block {\n        ProtoVersionedBlock::V1(v1_inner) => {\n            let proto_header = v1_inner\n                .header\n                .ok_or_else(|| anyhow::anyhow!(\"Missing protobuf header\"))\n                .map_err(Error::Serialization)?;\n            let (partial_header, event_inbox_root) =\n                partial_header_from_proto_header(&proto_header)?;\n            let txs = v1_inner\n                .transactions\n                .iter()\n                .map(tx_from_proto_tx)\n                .collect::<crate::result::Result<_>>()?;\n            let receipts = v1_inner\n                .receipts\n                .iter()\n                .map(|rs| {\n                    rs.receipts\n                        .iter()\n                        .map(receipt_from_proto)\n                        .collect::<crate::result::Result<Vec<_>>>()\n                })\n                .collect::<crate::result::Result<Vec<_>>>()?;","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs#L494-L530","documentation":"While decoding a V1 proto block, fuel_block_from_protobuf requires the header sub-message on the V1Block; prost yields None when absent and the code maps it to Error::Serialization. A V1 block without a header cannot produce a FuelBlockHeader, so the decode aborts.","triggerScenarios":"fuel_block_from_protobuf on a ProtoBlock whose V1 payload omitted header - encoder bug, truncated message, or a schema-skewed producer.","commonSituations":"Version mismatch between fuel-core releases; hand-built test blocks that fill only transactions/receipts; corruption.","solutions":["Debug-print the V1Block to confirm header is the only missing piece.","Fix the producer to always set header (see ProtobufBlockConverter::convert_block, which always attaches Some(proto_header)).","Pre-validate v1.header.is_some() after decode and reject with block-level context.","Re-fetch the block from a compatible peer."],"exampleFix":"// before\nlet (block, receipts) = fuel_block_from_protobuf(proto_block)?;\n\n// after: structural pre-check on the versioned payload\nif let Some(ProtoVersionedBlock::V1(v1)) = proto_block.versioned_block.as_ref() {\n    if v1.header.is_none() {\n        return Err(Error::Serialization(anyhow::anyhow!(\n            \"V1 block payload missing header\"\n        )));\n    }\n}","handlingStrategy":"type-guard","validationCode":"fn v1_block_has_header(v1: &ProtoV1Block) -> bool {\n    v1.header.is_some()\n}","typeGuard":"fn v1_block_decodable(v1: &ProtoV1Block) -> bool {\n    v1.header.is_some()\n}","tryCatchPattern":"match fuel_block_from_protobuf(proto_block) {\n    Ok((block, receipts)) => Ok((block, receipts)),\n    Err(Error::Serialization(ctx)) if ctx.to_string().contains(\"header\") => {\n        tracing::warn!(\"V1 payload missing header; re-fetching\");\n        fetch_block_from_peer(height)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Encoders must always attach Some(header) (mirror ProtobufBlockConverter::convert_block).","Structurally validate the versioned payload (header present) before deep conversion.","Reject blocks from schema-incompatible versions."],"tags":["rust","fuel-core","protobuf","deserialization","missing-field","block-header"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}