{"record":{"id":"ab5d9e6bd7eda91d","repo":"FuelLabs/fuel-core","slug":"could-not-convert-bytecode-witness-index-to-u16","errorCode":null,"errorMessage":"Could not convert bytecode_witness_index to u16: {}","messagePattern":"Could not convert bytecode_witness_index to u16: (.+?)","errorType":"exception","errorClass":"Error::Serialization","httpStatus":null,"severity":"error","filePath":"crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs","lineNumber":652,"sourceCode":"                .iter()\n                .map(output_from_proto_output)\n                .collect::<crate::result::Result<Vec<_>>>()?;\n            let witnesses = proto_create\n                .witnesses\n                .iter()\n                .map(|w| Ok(Witness::from(w.clone())))\n                .collect::<crate::result::Result<Vec<_>>>()?;\n            let storage_slots = proto_create\n                .storage_slots\n                .iter()\n                .map(storage_slot_from_proto)\n                .collect::<crate::result::Result<Vec<_>>>()?;\n            let salt =\n                fuel_core_types::fuel_types::Salt::try_from(proto_create.salt.as_slice())\n                    .map_err(|e| Error::Serialization(anyhow!(e)))?;\n            let bytecode_witness_index =\n                u16::try_from(proto_create.bytecode_witness_index).map_err(|e| {\n                    Error::Serialization(anyhow!(\n                        \"Could not convert bytecode_witness_index to u16: {}\",\n                        e\n                    ))\n                })?;\n\n            let create_tx = FuelTransaction::create(\n                bytecode_witness_index,\n                policies,\n                salt,\n                storage_slots,\n                inputs,\n                outputs,\n                witnesses,\n            );\n\n            Ok(FuelTransaction::Create(create_tx))\n        }\n        ProtoTransactionVariant::Mint(proto_mint) => {","sourceCodeStart":634,"sourceCodeEnd":670,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/services/block_aggregator_api/src/blocks/old_block_source/convertor_adapter/proto_to_fuel_conversions.rs#L634-L670","documentation":"The proto Create transaction stores bytecode_witness_index as a wide uint (the fuel-to-proto direction widens fuel-core's u16), and the reverse conversion u16::try_from fails when the value exceeds 65535, wrapped as Error::Serialization. fuel-core's Create transaction type requires u16, so out-of-range values are unrepresentable.","triggerScenarios":"Decoding a ProtoTransaction::Create whose bytecode_witness_index exceeds u16::MAX - only possible when the proto was not produced by fuel-core's own encoder (which always writes valid u16 values), e.g. hand-crafted messages, corrupted integers, or fuzz input.","commonSituations":"Third-party tools generating the protobuf format without fuel-core's bounds; fuzz/corpus testing with unconstrained integers; corrupted numeric fields.","solutions":["Log proto_create.bytecode_witness_index to confirm the out-of-range value.","Fix the producer to bound the field to 0..=65535 and to a valid witness index for the tx.","Pre-validate the range before decoding and reject the block early.","Treat payloads from non-fuel-core encoders as untrusted input."],"exampleFix":"// before\nlet bytecode_witness_index =\n    u16::try_from(proto_create.bytecode_witness_index).map_err(|e| {\n        Error::Serialization(anyhow!(\"Could not convert bytecode_witness_index to u16: {}\", e))\n    })?;\n\n// after: caller-side range check with context\nif proto_create.bytecode_witness_index > u16::MAX as u32 {\n    return Err(Error::Serialization(anyhow::anyhow!(\n        \"bytecode_witness_index {} exceeds u16::MAX\",\n        proto_create.bytecode_witness_index\n    )));\n}","handlingStrategy":"validation","validationCode":"fn bytecode_witness_index_valid(create: &ProtoCreate) -> bool {\n    create.bytecode_witness_index <= u16::MAX as u32\n}","typeGuard":"fn bytecode_witness_index_in_range(create: &ProtoCreate) -> bool {\n    create.bytecode_witness_index <= u16::MAX as u32\n}","tryCatchPattern":"match tx_from_proto_tx(t) {\n    Ok(tx) => txs.push(tx),\n    Err(Error::Serialization(ctx)) if ctx.to_string().contains(\"bytecode_witness_index\") => {\n        tracing::warn!(idx = create.bytecode_witness_index, \"rejecting Create tx with out-of-range witness index\");\n        return Err(Error::Serialization(ctx));\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Range-check integer fields against fuel-core type bounds (u16 here) at the trust boundary.","Only accept proto from producers that mirror fuel-core's encoder (u16 widened to u32).","In fuzz tests, constrain generated integers to realistic ranges to keep corpora meaningful."],"tags":["rust","fuel-core","protobuf","deserialization","integer-overflow","transactions"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}