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

Could not convert recipient to Address: {}

Error message

Could not convert recipient to Address: {}

What it means

The companion check to error 197: MessageCoinSigned recipient bytes must convert to a 32-byte Address. Address::try_from on proto_message.recipient fails for any length other than 32 and is reported as 'Could not convert recipient to Address: {e}'.

Source

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

                proto_coin_predicate.predicate.clone(),
                proto_coin_predicate.predicate_data.clone(),
            ))
        }
        ProtoInputVariant::Contract(proto_contract) => {
            let contract = contract_input_from_proto(proto_contract)?;
            Ok(Input::Contract(contract))
        }
        ProtoInputVariant::MessageCoinSigned(proto_message) => {
            let sender =
                Address::try_from(proto_message.sender.as_slice()).map_err(|e| {
                    Error::Serialization(anyhow!(
                        "Could not convert sender to Address: {}",
                        e
                    ))
                })?;
            let recipient = Address::try_from(proto_message.recipient.as_slice())
                .map_err(|e| {
                    Error::Serialization(anyhow!(
                        "Could not convert recipient to Address: {}",
                        e
                    ))
                })?;
            let nonce = fuel_core_types::fuel_types::Nonce::try_from(
                proto_message.nonce.as_slice(),
            )
            .map_err(|e| Error::Serialization(anyhow!(e)))?;
            let witness_index =
                u16::try_from(proto_message.witness_index).map_err(|e| {
                    Error::Serialization(anyhow!(
                        "Could not convert witness_index to u16: {}",
                        e
                    ))
                })?;

            Ok(Input::message_coin_signed(
                sender,

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Validate both sender and recipient are 32 bytes before converting message inputs
  2. Fix the producer to always set the recipient Address on message coins
  3. Reject unspendable messages (empty recipient) at ingestion with a targeted message instead of a generic conversion error
  4. Add round-trip serialization tests for message inputs in the producer

Example fix

// before
let recipient = Address::try_from(proto_message.recipient.as_slice()).map_err(...)?;

// after
for (name, b) in [("sender", &proto_message.sender), ("recipient", &proto_message.recipient)] {
    if b.len() != 32 { return Err(anyhow!("message {name} len {} != 32", b.len())); }
}
let recipient = Address::try_from(proto_message.recipient.as_slice()).map_err(...)?;
Defensive patterns

Strategy: validation

Validate before calling

fn message_input_is_valid(m: &ProtoMessageCoinSigned) -> bool {
    m.sender.len() == 32 && m.recipient.len() == 32 && m.nonce.len() == 32
}

Type guard

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

Try / catch

let recipient = Address::try_from(m.recipient.as_slice())
    .with_context(|| format!("message recipient len {} (expected 32)", m.recipient.len()))?;

Prevention

When it happens

Trigger: A message-coin input whose recipient is unset (0 bytes) or a non-32-byte value; sender may have passed just before this check fails.

Common situations: Bridge/relay producers that drop recipient on failure paths; address-format mismatches from other ecosystems; truncated payloads; incomplete test messages.

Related errors


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