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

Could not convert owner to Address: {}

Error message

Could not convert owner to Address: {}

What it means

For a CoinSigned input, the owner bytes must convert to fuel_types::Address, a fixed 32-byte type. Address::try_from fails on any length other than 32 (including the empty default when the producer never set owner), and the failure is wrapped as 'Could not convert owner to Address: {e}'.

Source

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

    }
}

fn input_from_proto_input(proto_input: &ProtoInput) -> crate::result::Result<Input> {
    let variant = proto_input
        .variant
        .as_ref()
        .ok_or_else(|| Error::Serialization(anyhow!("Missing input variant")))?;

    match variant {
        ProtoInputVariant::CoinSigned(proto_coin_signed) => {
            let utxo_proto = proto_coin_signed
                .utxo_id
                .as_ref()
                .ok_or_else(|| Error::Serialization(anyhow!("Missing utxo_id")))?;
            let utxo_id = utxo_id_from_proto(utxo_proto)?;
            let owner =
                Address::try_from(proto_coin_signed.owner.as_slice()).map_err(|e| {
                    Error::Serialization(anyhow!(
                        "Could not convert owner to Address: {}",
                        e
                    ))
                })?;
            let asset_id = fuel_core_types::fuel_types::AssetId::try_from(
                proto_coin_signed.asset_id.as_slice(),
            )
            .map_err(|e| Error::Serialization(anyhow!(e)))?;
            let tx_pointer_proto = proto_coin_signed
                .tx_pointer
                .as_ref()
                .ok_or_else(|| Error::Serialization(anyhow!("Missing tx_pointer")))?;
            let tx_pointer = tx_pointer_from_proto(tx_pointer_proto)?;
            let witness_index =
                u16::try_from(proto_coin_signed.witness_index).map_err(|e| {
                    Error::Serialization(anyhow!(
                        "Could not convert witness_index to u16: {}",
                        e

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Validate owner.len() == 32 on every coin input before running the conversion
  2. Fix the producer to serialize the full 32-byte Fuel Address
  3. If the source uses another address format, convert it explicitly at the boundary (e.g., left-pad/hash) rather than passing raw bytes
  4. Include the failing input's index and actual length in your validation logs to speed up producer-side fixes

Example fix

// before
let owner = Address::try_from(proto_coin_signed.owner.as_slice()).map_err(...)?;

// after
const ADDR_LEN: usize = 32;
if proto_coin_signed.owner.len() != ADDR_LEN {
    return Err(anyhow!("coin owner len {} != {ADDR_LEN}", proto_coin_signed.owner.len()));
}
let owner = Address::try_from(proto_coin_signed.owner.as_slice()).map_err(...)?;
Defensive patterns

Strategy: validation

Validate before calling

fn owner_is_valid_address(c: &ProtoCoinSigned) -> bool { c.owner.len() == 32 }

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: CoinSigned input with owner field unset (0 bytes — prost default) or wrong length (e.g., 20-byte EVM-style address, 64-byte key). The underlying try_from error is chained in the message.

Common situations: Producer omitted owner; address encoded from another ecosystem with different width; truncated payloads; test fixtures with placeholder addresses.

Related errors


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