{"record":{"id":"547d86266296b740","repo":"hyperledger/fabric","slug":"invalid-signed-proposal-during-check-policy-on-cha","errorCode":null,"errorMessage":"Invalid signed proposal during check policy on channel [%s] with policy [%s]","messagePattern":"Invalid signed proposal during check policy on channel \\[(.+?)\\] with policy \\[(.+?)\\]","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/policy/policy.go","lineNumber":71,"sourceCode":"\t\tchannelPolicyManagerGetter: channelPolicyManagerGetter,\n\t\tlocalMSP:                   localMSP,\n\t\tprincipalGetter:            &localMSPPrincipalGetter{localMSP: localMSP},\n\t}\n}\n\n// CheckPolicy checks that the passed signed proposal is valid with the respect to\n// passed policy on the passed channel.\nfunc (p *policyChecker) CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error {\n\tif channelID == \"\" {\n\t\treturn p.CheckPolicyNoChannel(policyName, signedProp)\n\t}\n\n\tif policyName == \"\" {\n\t\treturn fmt.Errorf(\"Invalid policy name during check policy on channel [%s]. Name must be different from nil.\", channelID)\n\t}\n\n\tif signedProp == nil {\n\t\treturn fmt.Errorf(\"Invalid signed proposal during check policy on channel [%s] with policy [%s]\", channelID, policyName)\n\t}\n\n\t// Get Policy\n\tpolicyManager := p.channelPolicyManagerGetter.Manager(channelID)\n\tif policyManager == nil {\n\t\treturn fmt.Errorf(\"Failed to get policy manager for channel [%s]\", channelID)\n\t}\n\n\t// Prepare SignedData\n\tproposal, err := protoutil.UnmarshalProposal(signedProp.ProposalBytes)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failing extracting proposal during check policy on channel [%s] with policy [%s]: [%s]\", channelID, policyName, err)\n\t}\n\n\theader, err := protoutil.UnmarshalHeader(proposal.Header)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Failing extracting header during check policy on channel [%s] with policy [%s]: [%s]\", channelID, policyName, err)\n\t}","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/policy/policy.go#L53-L89","documentation":"CheckPolicy requires a *pb.SignedProposal to evaluate signatures; a nil proposal is rejected with this message. Without proposal bytes and signature there is nothing to verify against the named policy.","triggerScenarios":"Calling CheckPolicy with signedProp == nil, e.g., evaluating a proposal collected from a nil source, or a caller that drops the proposal when unwrapping an inbound gRPC message.","commonSituations":"Endorsement/validation glue code that passes nil on a code path meant for internal checks, mis-wired proposal handlers, tests invoking CheckPolicy without constructing a SignedProposal.","solutions":["Construct a valid SignedProposal (ProposalBytes + Signature + Creator) before calling CheckPolicy","Guard the call site: return an explicit error when the proposal is nil instead of reaching the checker","If verifying raw signature data, use the lower-level policy.Evaluate(SignedData) API instead of CheckPolicy","Trace where the proposal originates (deliver/endorse handler) and fix the path that produces nil"],"exampleFix":"// before\nerr := checker.CheckPolicy(channelID, policyName, nil)\n// after\nif signedProp == nil {\n    return errors.New(\"signed proposal required\")\n}\nerr := checker.CheckPolicy(channelID, policyName, signedProp)","handlingStrategy":"validation","validationCode":"if signedProp == nil {\n    return errors.New(\"CheckPolicy requires a non-nil SignedProposal\")\n}\nif len(signedProp.ProposalBytes) == 0 || len(signedProp.Signature) == 0 {\n    return errors.New(\"SignedProposal missing proposal bytes or signature\")\n}","typeGuard":"func isSignedProposalValid(sp *pb.SignedProposal) bool {\n    return sp != nil && len(sp.ProposalBytes) > 0 && len(sp.Signature) > 0\n}","tryCatchPattern":"if err := checker.CheckPolicy(channelID, policyName, signedProp); err != nil {\n    if strings.HasPrefix(err.Error(), \"Invalid signed proposal during check policy\") {\n        // reconstruct SignedProposal from the inbound request before retrying\n    }\n    return err\n}","preventionTips":["Never pass nil proposals; short-circuit with a descriptive error in your handler","Build SignedProposal from the original inbound payload, keeping ProposalBytes and Signature together","Use policy.Evaluate(SignedData) directly when you only have signature data, not a proposal"],"tags":["hyperledger-fabric","policy","proposal","nil-check"],"backgroundTag":"nil-required-argument","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"}