FuelLabs/fuel-core · error · Error::Serialization

Could not convert storage slot key to Bytes32: {}

Error message

Could not convert storage slot key to Bytes32: {}

What it means

Thrown by storage_slot_from_proto when converting a proto Create-transaction storage slot: Bytes32::try_from(&[u8]) accepts exactly 32 bytes, and the proto key field has a different length. Wrapped as Error::Serialization, it aborts conversion of the storage slot, then the containing Create transaction and the whole block.

Source

Thrown at crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs:92

        SubAssetId,
    },
    tai64,
};

fn tx_pointer_from_proto(proto: &ProtoTxPointer) -> crate::result::Result<TxPointer> {
    let block_height = proto.block_height.into();
    #[allow(clippy::useless_conversion)]
    let tx_index = proto.tx_index.try_into().map_err(|e| {
        Error::Serialization(anyhow!("Could not convert tx_index to target type: {}", e))
    })?;
    Ok(TxPointer::new(block_height, tx_index))
}

fn storage_slot_from_proto(
    proto: &ProtoStorageSlot,
) -> crate::result::Result<StorageSlot> {
    let key = Bytes32::try_from(proto.key.as_slice()).map_err(|e| {
        Error::Serialization(anyhow!(
            "Could not convert storage slot key to Bytes32: {}",
            e
        ))
    })?;
    let value = Bytes32::try_from(proto.value.as_slice()).map_err(|e| {
        Error::Serialization(anyhow!(
            "Could not convert storage slot value to Bytes32: {}",
            e
        ))
    })?;
    Ok(StorageSlot::new(key, value))
}

fn contract_input_from_proto(
    proto: &ProtoContractInput,
) -> crate::result::Result<fuel_core_types::fuel_tx::input::contract::Contract> {
    let utxo_proto = proto.utxo_id.as_ref().ok_or_else(|| {
        Error::Serialization(anyhow!("Missing utxo_id on contract input"))

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Log the actual key length of the failing slot to confirm the mismatch.
  2. Validate all fixed-size byte fields (len == 32) at the trust boundary before calling fuel_block_from_protobuf.
  3. Ensure producer and consumer run the same fuel-core version so Bytes32 fields are always serialized as exactly 32 bytes.
  4. Re-fetch or re-encode the block from a known-good source; do not pad or truncate unless you own the data end to end.

Example fix

// before: convert directly and fail deep inside decoding
let storage_slots: Vec<StorageSlot> = proto_create.storage_slots.iter()
    .map(storage_slot_from_proto).collect::<Result<_>>()?;

// after: validate first, fail fast with slot position
for (i, slot) in proto_create.storage_slots.iter().enumerate() {
    if slot.key.len() != 32 || slot.value.len() != 32 {
        return Err(Error::Serialization(anyhow::anyhow!(
            "storage slot {} has key.len={} value.len={}; expected 32/32",
            i, slot.key.len(), slot.value.len()
        )));
    }
}
Defensive patterns

Strategy: validation

Validate before calling

fn storage_slots_valid(create: &ProtoCreate) -> bool {
    create.storage_slots.iter().all(|s| s.key.len() == 32 && s.value.len() == 32)
}

Type guard

fn is_bytes32(b: &[u8]) -> bool { b.len() == 32 }

Try / catch

match storage_slot_from_proto(slot) {
    Ok(s) => slots.push(s),
    Err(Error::Serialization(ctx)) if ctx.to_string().contains("storage slot") => {
        tracing::warn!(key_len = slot.key.len(), "rejecting malformed storage slot");
        return Err(Error::Serialization(ctx)); // or skip tx per policy
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: fuel_block_from_protobuf on a block where some ProtoStorageSlot.key is empty or any length other than 32 - typically corrupted blobs, truncated network frames, or a producer that writes unbounded bytes fields instead of fixed 32-byte keys.

Common situations: Proto produced by an incompatible fuel-core version or a hand-built serializer; data corrupted in transit or on disk; tests using arbitrary byte vectors instead of fixed 32-byte keys.

Related errors


AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16). Data as JSON: /api/errors/cd2f068a7e30aadb. Report an issue: GitHub.