FuelLabs/fuel-core · error · Error::Serialization
Could not convert log data digest to Bytes32: {}
Error message
Could not convert log data digest to Bytes32: {} What it means
Thrown while decoding a LogData receipt: the digest bytes field must be exactly 32 bytes for fuel's Bytes32; a different length fails try_from and is wrapped as Error::Serialization, aborting the receipt and block conversion.
Source
Thrown at crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs:388
)
}
ProtoReceiptVariant::Revert(revert) => {
let id = ContractId::try_from(revert.id.as_slice())
.map_err(|e| Error::Serialization(anyhow!(e)))?;
Ok(FuelReceipt::revert(id, revert.ra, revert.pc, revert.is))
}
ProtoReceiptVariant::Log(log) => {
let id = ContractId::try_from(log.id.as_slice())
.map_err(|e| Error::Serialization(anyhow!(e)))?;
Ok(FuelReceipt::log(
id, log.ra, log.rb, log.rc, log.rd, log.pc, log.is,
))
}
ProtoReceiptVariant::LogData(log) => {
let id = ContractId::try_from(log.id.as_slice())
.map_err(|e| Error::Serialization(anyhow!(e)))?;
let digest = Bytes32::try_from(log.digest.as_slice()).map_err(|e| {
Error::Serialization(anyhow!(
"Could not convert log data digest to Bytes32: {}",
e
))
})?;
Ok(FuelReceipt::log_data_with_len(
id,
log.ra,
log.rb,
log.ptr,
log.len,
digest,
log.pc,
log.is,
log.data.clone(),
))
}
ProtoReceiptVariant::Transfer(transfer) => {
let id = ContractId::try_from(transfer.id.as_slice())View on GitHub (pinned to b9d4d170da)
Solutions
- Log the digest length of the failing LogData receipt.
- Pre-validate len == 32 for all receipt digest fields before decoding.
- Pin matching fuel-core versions on both ends.
- Reject and re-fetch the block.
Example fix
// before
let digest = Bytes32::try_from(log.digest.as_slice()).map_err(|e| {
Error::Serialization(anyhow!("Could not convert log data digest to Bytes32: {}", e))
})?;
// after
if log.digest.len() != 32 {
return Err(Error::Serialization(anyhow::anyhow!(
"LogData digest length {} != 32", log.digest.len()
)));
} Defensive patterns
Strategy: validation
Validate before calling
fn log_data_digest_valid(log: &ProtoLogData) -> bool {
log.digest.len() == 32
} Type guard
fn is_bytes32(b: &[u8]) -> bool { b.len() == 32 } Try / catch
match receipt_from_proto(r) {
Ok(receipt) => out.push(receipt),
Err(Error::Serialization(ctx)) if ctx.to_string().contains("log data digest") => {
tracing::warn!(len = log.digest.len(), "rejecting LogData with bad digest");
return Err(Error::Serialization(ctx));
}
Err(e) => return Err(e),
} Prevention
- Validate digest length on LogData receipts before decoding blocks.
- Keep encoder/decoder versions aligned; checksum stored blobs.
- Build test receipts through fuel-core constructors so digests are always 32 bytes.
When it happens
Trigger: fuel_block_from_protobuf on a block where a LogData receipt's digest has a length other than 32 - corruption, truncation, or an encoder that does not fix the digest size.
Common situations: Producer/consumer version mismatch; corrupted transfer; hand-built receipts in tests.
Related errors
- Could not convert return data digest to Bytes32: {}
- Could not convert message digest to Bytes32: {}
- Could not convert storage slot key to Bytes32: {}
- Could not convert storage slot value to Bytes32: {}
- Could not convert balance_root to Bytes32: {}
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/d22f3ec2f705374b.
Report an issue: GitHub.