{"record":{"id":"246b26d580b7a5f3","repo":"FuelLabs/fuel-core","slug":"could-not-convert-proof-set-entry-to-bytes32","errorCode":null,"errorMessage":"Could not convert proof_set entry to Bytes32: {}","messagePattern":"Could not convert proof_set entry to Bytes32: (.+?)","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":794,"sourceCode":"                u16::try_from(proto_upload.subsection_index).map_err(|e| {\n                    Error::Serialization(anyhow!(\n                        \"Could not convert subsection_index to u16: {}\",\n                        e\n                    ))\n                })?;\n            let subsections_number = u16::try_from(proto_upload.subsections_number)\n                .map_err(|e| {\n                    Error::Serialization(anyhow!(\n                        \"Could not convert subsections_number to u16: {}\",\n                        e\n                    ))\n                })?;\n            let proof_set = proto_upload\n                .proof_set\n                .iter()\n                .map(|entry| {\n                    Bytes32::try_from(entry.as_slice()).map_err(|e| {\n                        Error::Serialization(anyhow!(\n                            \"Could not convert proof_set entry to Bytes32: {}\",\n                            e\n                        ))\n                    })\n                })\n                .collect::<crate::result::Result<Vec<_>>>()?;\n\n            let body = UploadBody {\n                root,\n                witness_index,\n                subsection_index,\n                subsections_number,\n                proof_set,\n            };\n\n            let upload_tx =\n                FuelTransaction::upload(body, policies, inputs, outputs, witnesses);\n","sourceCodeStart":776,"sourceCodeEnd":812,"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#L776-L812","documentation":"The upload proof_set is a list of 32-byte Merkle proofs. Each entry goes through Bytes32::try_from(entry.as_slice()); any entry whose length is not exactly 32 bytes fails and is wrapped with this message, failing the whole Upload conversion.","triggerScenarios":"An Upload proto where one or more proof_set entries are empty (producer pushed Vec::new()) or wrong-length (31/33 bytes) due to an encoder bug or payload corruption. Note the check runs per entry, so one bad proof invalidates the transaction even if the root is valid.","commonSituations":"Producer building proofs with a different hash width; empty proof vectors used as placeholders; truncation in transport/storage; test fixtures with dummy proofs.","solutions":["Pre-validate: all proof_set entries must be exactly 32 bytes; report which index failed","Fix the producer's Merkle proof generation to emit fuel-core-sized (32-byte) proofs","Recompute the proof set from the blob root and subsection data instead of trusting the wire value if the source is recoverable","Add payload integrity checks (re-serialization round-trip) at ingestion"],"exampleFix":"// before\nlet proof_set = proto_upload.proof_set.iter().map(|e| Bytes32::try_from(e.as_slice()).map_err(...)).collect::<Result<Vec<_>>>()?;\n\n// after\nif let Some(i) = proto_upload.proof_set.iter().position(|e| e.len() != 32) {\n    return Err(anyhow!(\"proof_set[{i}] has {} bytes, expected 32\", proto_upload.proof_set[i].len()));\n}\nlet proof_set = proto_upload.proof_set.iter().map(|e| Bytes32::try_from(e.as_slice()).unwrap()).collect::<Vec<_>>();","handlingStrategy":"validation","validationCode":"fn proof_set_is_valid(u: &ProtoUpload) -> bool {\n    !u.proof_set.is_empty() && u.proof_set.iter().all(|e| e.len() == 32)\n}","typeGuard":"fn proof_entry_ok(e: &[u8]) -> bool { e.len() == 32 }","tryCatchPattern":"for (i, entry) in u.proof_set.iter().enumerate() {\n    Bytes32::try_from(entry.as_slice())\n        .with_context(|| format!(\"proof_set[{i}] len {}\", entry.len()))?;\n}","preventionTips":["Validate every vector element's width, not just the first","Generate proofs with the same 32-byte hash function the chain uses","Include the failing index in error context so producers can locate the bug"],"tags":["rust","fuel","protobuf","serialization","upload-transaction","bytes32","merkle-proof","validation"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}