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: {}",
eView on GitHub (pinned to b9d4d170da)
Solutions
- Validate owner.len() == 32 on every coin input before running the conversion
- Fix the producer to serialize the full 32-byte Fuel Address
- If the source uses another address format, convert it explicitly at the boundary (e.g., left-pad/hash) rather than passing raw bytes
- 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
- Check fixed widths (32 bytes) before try_from on every address-like field
- Convert foreign address formats at the ingestion boundary, never implicitly
- Fail loudly in producer unit tests when addresses are not 32 bytes
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
- Could not convert sender to Address: {}
- Could not convert recipient to Address: {}
- Could not convert upload root to Bytes32: {}
- Could not convert witness_index to u16: {}
- Could not convert subsection_index to u16: {}
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/33ea54750751c02a.
Report an issue: GitHub.