{"record":{"id":"3a09bf5c9b9bf6f1","repo":"FuelLabs/fuel-core","slug":"missing-script-result-payload","errorCode":null,"errorMessage":"Missing script result payload","messagePattern":"Missing script result payload","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":439,"sourceCode":"        ProtoReceiptVariant::TransferOut(transfer) => {\n            let id = ContractId::try_from(transfer.id.as_slice())\n                .map_err(|e| Error::Serialization(anyhow!(e)))?;\n            let to = Address::try_from(transfer.to.as_slice())\n                .map_err(|e| Error::Serialization(anyhow!(e)))?;\n            let asset_id = AssetId::try_from(transfer.asset_id.as_slice())\n                .map_err(|e| Error::Serialization(anyhow!(e)))?;\n            Ok(FuelReceipt::transfer_out(\n                id,\n                to,\n                transfer.amount,\n                asset_id,\n                transfer.pc,\n                transfer.is,\n            ))\n        }\n        ProtoReceiptVariant::ScriptResult(result) => {\n            let script_result = result.result.as_ref().ok_or_else(|| {\n                Error::Serialization(anyhow!(\"Missing script result payload\"))\n            })?;\n            let execution_result = script_execution_result_from_proto(script_result)?;\n            Ok(FuelReceipt::script_result(\n                execution_result,\n                result.gas_used,\n            ))\n        }\n        ProtoReceiptVariant::MessageOut(msg) => {\n            let sender = Address::try_from(msg.sender.as_slice())\n                .map_err(|e| Error::Serialization(anyhow!(e)))?;\n            let recipient = Address::try_from(msg.recipient.as_slice())\n                .map_err(|e| Error::Serialization(anyhow!(e)))?;\n            let nonce = Nonce::try_from(msg.nonce.as_slice())\n                .map_err(|e| Error::Serialization(anyhow!(e)))?;\n            let digest = Bytes32::try_from(msg.digest.as_slice()).map_err(|e| {\n                Error::Serialization(anyhow!(\n                    \"Could not convert message digest to Bytes32: {}\",\n                    e","sourceCodeStart":421,"sourceCodeEnd":457,"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#L421-L457","documentation":"receipt_from_proto requires the ScriptResult receipt's result sub-message, which carries the ScriptExecutionResult; prost yields None when it is absent, and the code maps that to Error::Serialization. Without it there is no way to build FuelReceipt::script_result, so the block decode fails.","triggerScenarios":"Decoding a proto block where a ScriptResult receipt omits the nested result message - encoder skips it, data truncated, or a fixture that sets only gas_used.","commonSituations":"Version skew across schema changes; producers that write partial receipts; fuzzing.","solutions":["Debug-print the failing ScriptResult receipt to confirm result is None.","Fix the encoder to always embed the ScriptExecutionResult sub-message.","Pre-validate presence of result on ScriptResult receipts before decoding.","Re-fetch the block from a compatible peer."],"exampleFix":"// before\nlet script_result = result.result.as_ref().ok_or_else(|| {\n    Error::Serialization(anyhow!(\"Missing script result payload\"))\n})?;\n\n// after: pre-validate with position context\nif let ProtoReceiptVariant::ScriptResult(sr) = variant {\n    if sr.result.is_none() {\n        return Err(Error::Serialization(anyhow::anyhow!(\n            \"receipt[{i}] ScriptResult missing result payload\"\n        )));\n    }\n}","handlingStrategy":"type-guard","validationCode":"fn script_result_payload_present(sr: &ProtoScriptResult) -> bool {\n    sr.result.is_some()\n}","typeGuard":"fn script_result_complete(sr: &ProtoScriptResult) -> bool {\n    sr.result.is_some()\n}","tryCatchPattern":"match receipt_from_proto(r) {\n    Ok(receipt) => out.push(receipt),\n    Err(Error::Serialization(ctx)) if ctx.to_string().contains(\"script result\") => {\n        tracing::warn!(?r, \"rejecting ScriptResult without payload\");\n        return Err(Error::Serialization(ctx));\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Encoders must always embed the ScriptExecutionResult sub-message in ScriptResult receipts.","Pre-validate nested presence for oneof receipt variants after decode.","Reject schema-drifted peers instead of lenient decoding."],"tags":["rust","fuel-core","protobuf","deserialization","receipts","missing-field"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}