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

Could not convert witness_index to u16: {}

Error message

Could not convert witness_index to u16: {}

What it means

The proto field witness_index is a wider integer (u32/i32) but the fuel-core UploadBody stores it as u16. u16::try_from fails when the value exceeds 65535 (or is negative when the proto field is int32), producing this Error::Serialization.

Source

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

            let outputs = proto_upload
                .outputs
                .iter()
                .map(output_from_proto_output)
                .collect::<crate::result::Result<Vec<_>>>()?;
            let witnesses = proto_upload
                .witnesses
                .iter()
                .map(|w| Ok(Witness::from(w.clone())))
                .collect::<crate::result::Result<Vec<_>>>()?;
            let root = Bytes32::try_from(proto_upload.root.as_slice()).map_err(|e| {
                Error::Serialization(anyhow!(
                    "Could not convert upload root to Bytes32: {}",
                    e
                ))
            })?;
            let witness_index =
                u16::try_from(proto_upload.witness_index).map_err(|e| {
                    Error::Serialization(anyhow!(
                        "Could not convert witness_index to u16: {}",
                        e
                    ))
                })?;
            let subsection_index =
                u16::try_from(proto_upload.subsection_index).map_err(|e| {
                    Error::Serialization(anyhow!(
                        "Could not convert subsection_index to u16: {}",
                        e
                    ))
                })?;
            let subsections_number = u16::try_from(proto_upload.subsections_number)
                .map_err(|e| {
                    Error::Serialization(anyhow!(
                        "Could not convert subsections_number to u16: {}",
                        e
                    ))
                })?;

View on GitHub (pinned to b9d4d170da)

Solutions

  1. Fix the producer to cap witness_index at u16 (it indexes into the witnesses vector, so it must be < witnesses.len() anyway)
  2. Validate witness_index <= 65535 and < witnesses.len() before conversion and reject the transaction with a precise message
  3. If a sentinel like u32::MAX means 'unset' in your source data, map it explicitly during re-encoding instead of letting try_from fail
  4. Add proto-level contract tests asserting witness_index range for every upload transaction

Example fix

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

// after
let wi = proto_upload.witness_index;
if !(0..=u16::MAX as u32).contains(&wi) || wi as usize >= proto_upload.witnesses.len() {
    return Err(anyhow!("witness_index {wi} out of range (witnesses: {})", proto_upload.witnesses.len()));
}
let witness_index = wi as u16;
Defensive patterns

Strategy: validation

Validate before calling

fn upload_witness_index_ok(u: &ProtoUpload) -> bool {
    u.witness_index <= u16::MAX as u32 && (u.witness_index as usize) < u.witnesses.len()
}

Type guard

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

Try / catch

let witness_index = u16::try_from(u.witness_index).map_err(|_| {
    anyhow!("witness_index {} out of range for tx {:?}", u.witness_index, tx_id)
})?;

Prevention

When it happens

Trigger: An Upload proto with witness_index > 65535 (e.g., set to u32::MAX as a sentinel by a buggy producer) or a negative i32 from mis-typed encoders. Note: an unset proto field defaults to 0 and passes, so this specifically means a large out-of-range value was encoded.

Common situations: Cross-language encoders (Go/TS) that treat witness_index as varint without range checks; sentinel values like 0xFFFFFFFF used to mean 'none'; corrupted payloads.

Related errors


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