FuelLabs/fuel-core · error · Error::Serialization
Missing protobuf versioned_block
Error message
Missing protobuf versioned_block
What it means
fuel_block_from_protobuf unwraps the Block.versioned_block oneof; prost decodes bytes that set no recognized variant into None, and the code maps that to Error::Serialization. This is the outermost structural check: it fires before any header/tx/receipt field is read.
Source
Thrown at crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs:506
Ok(FuelReceipt::burn(
sub_id,
contract_id,
burn.val,
burn.pc,
burn.is,
))
}
}?;
Ok(receipt)
}
pub fn fuel_block_from_protobuf(
proto_block: ProtoBlock,
) -> crate::result::Result<(FuelBlock, Vec<Vec<FuelReceipt>>)> {
let versioned_block = proto_block
.versioned_block
.ok_or_else(|| anyhow::anyhow!("Missing protobuf versioned_block"))
.map_err(Error::Serialization)?;
let (partial_header, event_inbox_root, txs, receipts) = match versioned_block {
ProtoVersionedBlock::V1(v1_inner) => {
let proto_header = v1_inner
.header
.ok_or_else(|| anyhow::anyhow!("Missing protobuf header"))
.map_err(Error::Serialization)?;
let (partial_header, event_inbox_root) =
partial_header_from_proto_header(&proto_header)?;
let txs = v1_inner
.transactions
.iter()
.map(tx_from_proto_tx)
.collect::<crate::result::Result<_>>()?;
let receipts = v1_inner
.receipts
.iter()
.map(|rs| {View on GitHub (pinned to b9d4d170da)
Solutions
- Check the payload before decode: non-empty, plausible length, and ideally a checksum or length prefix from the sender.
- After ProtoBlock::decode, immediately assert versioned_block.is_some() and fail fast with payload metadata (len, first bytes) in the error.
- Pin producer and consumer to the same fuel-core/protobuf schema version; keep the crate's serialize_block__roundtrip test green across upgrades.
- Treat repeated occurrences as a protocol violation and drop or re-fetch from another peer.
Example fix
// before
let (block, receipts) = fuel_block_from_protobuf(proto_block)?;
// after: guard right after decode
let proto_block = ProtoBlock::decode(&*bytes)
.map_err(Error::serialization_error)?;
if proto_block.versioned_block.is_none() {
return Err(Error::Serialization(anyhow::anyhow!(
"payload of {} bytes has no versioned_block variant; wrong schema or corrupt data",
bytes.len()
)));
} Defensive patterns
Strategy: type-guard
Validate before calling
fn proto_block_has_versioned_payload(b: &ProtoBlock) -> bool {
b.versioned_block.is_some()
}
// right after decode
let proto_block = ProtoBlock::decode(&*bytes).map_err(Error::serialization_error)?;
assert!(proto_block_has_versioned_payload(&proto_block), "no versioned_block variant"); Type guard
fn proto_block_decodable(b: &ProtoBlock) -> bool {
matches!(b.versioned_block, Some(ProtoVersionedBlock::V1(_)))
} Try / catch
match fuel_block_from_protobuf(proto_block) {
Ok((block, receipts)) => Ok((block, receipts)),
Err(Error::Serialization(ctx)) if ctx.to_string().contains("versioned_block") => {
tracing::warn!(len = bytes.len(), "payload has no versioned_block; wrong schema or corrupt");
fetch_block_from_peer(height) // fallback source
}
Err(e) => Err(e),
} Prevention
- Never feed unvalidated bytes into fuel_block_from_protobuf; check non-empty and expected framing first.
- Version-negotiate with peers and pin compatible fuel-core builds.
- Keep the serialize_block__roundtrip test in CI across upgrades to catch schema drift early.
- Treat this error at a network boundary as a protocol violation, not a data quirk.
When it happens
Trigger: ProtoBlock::decode on empty or wrong-schema bytes succeeds (prost is lenient about unknown fields) but yields versioned_block == None; or the payload was encoded by a fuel-core version whose oneof tags differ from this build.
Common situations: Feeding truncated/garbage payloads into fuel_block_from_protobuf; cross-version block exchange where one side only knows V1 and the other emits a different variant; untrusted input at a network boundary.
Related errors
- Missing utxo_id on contract input
- Missing tx_pointer on contract input
- Missing receipt variant
- Missing panic reason
- Missing script result payload
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/a3cc094f6f54aeca.
Report an issue: GitHub.