FuelLabs/fuel-core · error · Error::Serialization
Missing input variant
Error message
Missing input variant
What it means
ProtoInput models inputs as a oneof variant; when the variant field itself is None there is no way to tell coin/message/contract apart, so input_from_proto_input fails fast with this serialization error before any field checks.
Source
Thrown at crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs:863
})?;
let body = BlobBody {
id: blob_id,
witness_index,
};
let blob_tx =
FuelTransaction::blob(body, policies, inputs, outputs, witnesses);
Ok(FuelTransaction::Blob(blob_tx))
}
}
}
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(),
)View on GitHub (pinned to b9d4d170da)
Solutions
- Fix the producer to always populate the input variant oneof when appending inputs
- Pre-scan inputs before conversion and reject transactions with variant-less ProtoInput entries, logging tx id and input position
- Align proto definitions between producer and this crate
- For legacy data, re-encode inputs with an explicit variant chosen from the transaction type context
Example fix
// before
let variant = proto_input.variant.as_ref().ok_or_else(|| Error::Serialization(anyhow!("Missing input variant")))?;
// after
let Some(variant) = proto_input.variant.as_ref() else {
// skip-and-report keeps one malformed input from killing the whole block ingest
report_bad_input(&proto_input);
continue;
}; Defensive patterns
Strategy: type-guard
Validate before calling
fn all_inputs_have_variants(tx: &ProtoTransaction) -> bool {
tx.inputs.iter().all(|i| i.variant.is_some())
} Type guard
fn input_variant_present(i: &ProtoInput) -> bool { i.variant.is_some() } Try / catch
let variant = i.variant.as_ref().ok_or_else(|| {
anyhow!("input #{idx} in tx {:?} has no variant — producer bug", tx_id)
})?; Prevention
- Prohibit bare ProtoInput in producer code (wrap construction in a builder that requires a variant)
- Scan whole transactions for variant-less inputs before starting conversion
- Track which producer version emitted malformed inputs via telemetry
When it happens
Trigger: A transaction input proto with the variant oneof never set — an encoder produced a bare ProtoInput, or the payload was truncated after the outer message. Any transaction type containing inputs (script, upload, blob, upgrade, mint) can surface this.
Common situations: Default-constructed ProtoInput structs (prost makes all-oneof-None valid); partial serialization from a buggy client; schema-skew where the input oneof was renamed.
Related errors
- Missing input_contract on mint transaction
- Missing output_contract on mint transaction
- Missing purpose on upgrade transaction
- Missing utxo_id
- Missing tx_pointer
AI-assisted analysis of FuelLabs/fuel-core@b9d4d170da (2026-08-16).
Data as JSON: /api/errors/4ba3429210991535.
Report an issue: GitHub.