{"record":{"id":"77968f5a87045785","repo":"hyperledger/fabric","slug":"empty-signature-bytes","errorCode":null,"errorMessage":"empty signature bytes","messagePattern":"empty signature bytes","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/endorser/msgvalidation.go","lineNumber":166,"sourceCode":"\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))\n\t\treturn genericAuthError\n\t}\n\n\tlogger = logger.With(\"mspID\", creator.GetMSPIdentifier())","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/endorser/msgvalidation.go#L148-L184","documentation":"The SignedProposal's Signature field is nil, so the endorser has nothing to cryptographically verify against the creator identity. Fabric requires every proposal to be signed by the submitting client's private key over the ProposalBytes.","triggerScenarios":"ProcessProposal -> preProcess -> Validate on a SignedProposal where Signature was never populated — e.g. building the proposal but skipping the signing step, or a signer returning nil on error that was ignored.","commonSituations":"Client wallet missing or private key not loadable so the sign call silently returned nil, custom protobuf assembly that sets ProposalBytes but not Signature, middleware stripping the signature.","solutions":["Sign the ProposalBytes with the creator's private key (ECDSA with SHA-256 in Fabric) and store the result in SignedProposal.Signature.","Check the signing identity/key is loaded and that the signer's error (if any) is not ignored before sending.","Use the SDK's sign/submit pipeline so signing happens automatically between proposal creation and dispatch."],"exampleFix":"// before\nsigned := &peer.SignedProposal{ProposalBytes: proposalBytes}\n// after\nsig, err := signer.Sign(proposalBytes)\nif err != nil { return err }\nsigned := &peer.SignedProposal{ProposalBytes: proposalBytes, Signature: sig}","handlingStrategy":"validation","validationCode":"if sp.Signature == nil || len(sp.Signature) == 0 {\n    return errors.New(\"proposal must be signed: sign ProposalBytes with the creator's private key\")\n}","typeGuard":"func isSigned(sp *peer.SignedProposal) bool {\n    return sp != nil && len(sp.Signature) > 0\n}","tryCatchPattern":null,"preventionTips":["Always run the SDK sign step between proposal creation and submit","Check signer errors; never send an unsigned proposal","Ensure the wallet/private key is available at submit time"],"tags":["hyperledger-fabric","endorser","signature","authentication"],"backgroundTag":"missing-proposal-signature","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"}