{"record":{"id":"f2885b0ff4fc2853","repo":"hyperledger/fabric","slug":"empty-proposal-bytes","errorCode":null,"errorMessage":"empty proposal bytes","messagePattern":"empty proposal bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/endorser/msgvalidation.go","lineNumber":162,"sourceCode":"\t}\n\n\t// ensure that there is a nonce\n\tif len(up.SignatureHeader.Nonce) == 0 {\n\t\treturn errors.Errorf(\"nonce is empty\")\n\t}\n\n\t// ensure that there is a creator\n\tif len(up.SignatureHeader.Creator) == 0 {\n\t\treturn errors.New(\"creator is empty\")\n\t}\n\n\texpectedTxID := protoutil.ComputeTxID(up.SignatureHeader.Nonce, up.SignatureHeader.Creator)\n\tif up.TxID() != expectedTxID {\n\t\treturn errors.Errorf(\"incorrectly computed txid '%s' -- expected '%s'\", up.TxID(), expectedTxID)\n\t}\n\n\tif up.SignedProposal.ProposalBytes == nil {\n\t\treturn errors.Errorf(\"empty proposal bytes\")\n\t}\n\n\tif up.SignedProposal.Signature == nil {\n\t\treturn errors.Errorf(\"empty signature bytes\")\n\t}\n\n\t// get the identity of the creator\n\tcreator, err := idDeserializer.DeserializeIdentity(up.SignatureHeader.Creator)\n\tif err != nil {\n\t\tlogger.Warnw(\"access denied\", \"error\", err, \"identity\", protoutil.LogMessageForSerializedIdentity(up.SignatureHeader.Creator))\n\t\treturn errors.Errorf(\"access denied: channel [%s] creator org unknown, creator is malformed\", up.ChannelID())\n\t}\n\n\tgenericAuthError := errors.Errorf(\"access denied: channel [%s] creator org [%s]\", up.ChannelID(), creator.GetMSPIdentifier())\n\t// ensure that creator is a valid certificate\n\terr = creator.Validate()\n\tif err != nil {\n\t\tlogger.Warnw(\"access denied: identity is not valid\", \"error\", err, \"identity\", protoutil.LogMessageForSerializedIdentity(up.SignatureHeader.Creator))","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/endorser/msgvalidation.go#L144-L180","documentation":"The SignedProposal's ProposalBytes field is nil, so there is no proposal payload to verify the signature against or to unpack. The endorser requires both ProposalBytes and Signature to be present in a SignedProposal.","triggerScenarios":"ProcessProposal -> preProcess -> Validate on a SignedProposal struct where ProposalBytes was never set — e.g. constructing SignedProposal{Signature: sig} without proposal marshaling, or a gRPC transmission that dropped the field.","commonSituations":"Manually assembled SignedProposal protobufs, clients that sign but forget to attach the marshaled Proposal message, serialization bugs where nil marshal produces empty bytes.","solutions":["Marshal the fully populated Proposal message with proto.Marshal and assign it to SignedProposal.ProposalBytes before signing.","Sign exactly the ProposalBytes slice and store both in the SignedProposal sent to ProcessProposal.","Assert both ProposalBytes and Signature are non-nil/non-empty before sending the gRPC request."],"exampleFix":"// before\nsigned := &peer.SignedProposal{Signature: sig}\n// after\nproposalBytes, _ := proto.Marshal(proposal)\nsigned := &peer.SignedProposal{ProposalBytes: proposalBytes, Signature: sig}","handlingStrategy":"validation","validationCode":"if sp.ProposalBytes == nil || len(sp.ProposalBytes) == 0 {\n    return errors.New(\"ProposalBytes must be the marshaled Proposal before sending\")\n}","typeGuard":"func hasProposalBytes(sp *peer.SignedProposal) bool {\n    return sp != nil && len(sp.ProposalBytes) > 0\n}","tryCatchPattern":null,"preventionTips":["Marshal the Proposal and assign ProposalBytes before signing","Sanity-check the SignedProposal fields before the gRPC call","Sign exactly the bytes you transmit"],"tags":["hyperledger-fabric","endorser","proposal-validation","malformed-message"],"backgroundTag":"empty-proposal-bytes","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}