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

Could not convert blob witness_index to u16: {}

Error message

Could not convert blob witness_index to u16: {}

What it means

Blob transactions reference their blob witness via BlobBody.witness_index, a u16 in fuel-core. The proto field is wider; u16::try_from fails for values above 65535 (or negative), raising this Error::Serialization while building the BlobBody.

Source

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

                .iter()
                .map(input_from_proto_input)
                .collect::<crate::result::Result<Vec<_>>>()?;
            let outputs = proto_blob
                .outputs
                .iter()
                .map(output_from_proto_output)
                .collect::<crate::result::Result<Vec<_>>>()?;
            let witnesses = proto_blob
                .witnesses
                .iter()
                .map(|w| Ok(Witness::from(w.clone())))
                .collect::<crate::result::Result<Vec<_>>>()?;
            let blob_id = fuel_core_types::fuel_types::BlobId::try_from(
                proto_blob.blob_id.as_slice(),
            )
            .map_err(|e| Error::Serialization(anyhow!(e)))?;
            let witness_index = u16::try_from(proto_blob.witness_index).map_err(|e| {
                Error::Serialization(anyhow!(
                    "Could not convert blob witness_index to u16: {}",
                    e
                ))
            })?;
            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> {

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Validate witness_index <= 65535 and < witnesses.len() before converting the Blob transaction
  2. Fix the producer to emit a real witness index (blob transactions must attach the blob as a witness)
  3. Map sentinel values explicitly during re-encoding rather than letting try_from fail
  4. Add encode/decode round-trip tests for blob transactions in the producer's test suite

Example fix

// before
let witness_index = u16::try_from(proto_blob.witness_index).map_err(...)?;

// after
let wi = proto_blob.witness_index;
if wi > u16::MAX as u32 || wi as usize >= proto_blob.witnesses.len() {
    return Err(anyhow!("blob witness_index {wi} invalid with {} witnesses", proto_blob.witnesses.len()));
}
let witness_index = wi as u16;
Defensive patterns

Strategy: validation

Validate before calling

fn blob_witness_index_ok(b: &ProtoBlob) -> bool {
    b.witness_index <= u16::MAX as u32 && (b.witness_index as usize) < b.witnesses.len()
}

Type guard

fn fits_u16(v: u32) -> bool { v <= u16::MAX as u32 }

Try / catch

let witness_index = u16::try_from(b.witness_index)
    .with_context(|| format!("blob witness_index {} with {} witnesses", b.witness_index, b.witnesses.len()))?;

Prevention

When it happens

Trigger: A Blob proto with witness_index > 65535 — typically a sentinel (u32::MAX / -1) meaning 'no witness', or a corrupted/mis-encoded payload. Valid transactions keep this well under the witness count.

Common situations: Cross-language encoders omitting range checks; sentinel values for optional witnesses; fuzzed data; version skew where a newer field semantics was back-filled into an old producer.

Related errors


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