hyperledger/fabric · error

Invalid signed proposal during check policy on channel [%s]

Error message

Invalid signed proposal during check policy on channel [%s] with policy [%s]

What it means

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.

Source

Thrown at core/policy/policy.go:71

		channelPolicyManagerGetter: channelPolicyManagerGetter,
		localMSP:                   localMSP,
		principalGetter:            &localMSPPrincipalGetter{localMSP: localMSP},
	}
}

// CheckPolicy checks that the passed signed proposal is valid with the respect to
// passed policy on the passed channel.
func (p *policyChecker) CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error {
	if channelID == "" {
		return p.CheckPolicyNoChannel(policyName, signedProp)
	}

	if policyName == "" {
		return fmt.Errorf("Invalid policy name during check policy on channel [%s]. Name must be different from nil.", channelID)
	}

	if signedProp == nil {
		return fmt.Errorf("Invalid signed proposal during check policy on channel [%s] with policy [%s]", channelID, policyName)
	}

	// Get Policy
	policyManager := p.channelPolicyManagerGetter.Manager(channelID)
	if policyManager == nil {
		return fmt.Errorf("Failed to get policy manager for channel [%s]", channelID)
	}

	// Prepare SignedData
	proposal, err := protoutil.UnmarshalProposal(signedProp.ProposalBytes)
	if err != nil {
		return fmt.Errorf("Failing extracting proposal during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err)
	}

	header, err := protoutil.UnmarshalHeader(proposal.Header)
	if err != nil {
		return fmt.Errorf("Failing extracting header during check policy on channel [%s] with policy [%s]: [%s]", channelID, policyName, err)
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Construct a valid SignedProposal (ProposalBytes + Signature + Creator) before calling CheckPolicy
  2. Guard the call site: return an explicit error when the proposal is nil instead of reaching the checker
  3. If verifying raw signature data, use the lower-level policy.Evaluate(SignedData) API instead of CheckPolicy
  4. Trace where the proposal originates (deliver/endorse handler) and fix the path that produces nil

Example fix

// before
err := checker.CheckPolicy(channelID, policyName, nil)
// after
if signedProp == nil {
    return errors.New("signed proposal required")
}
err := checker.CheckPolicy(channelID, policyName, signedProp)
Defensive patterns

Strategy: validation

Validate before calling

if signedProp == nil {
    return errors.New("CheckPolicy requires a non-nil SignedProposal")
}
if len(signedProp.ProposalBytes) == 0 || len(signedProp.Signature) == 0 {
    return errors.New("SignedProposal missing proposal bytes or signature")
}

Type guard

func isSignedProposalValid(sp *pb.SignedProposal) bool {
    return sp != nil && len(sp.ProposalBytes) > 0 && len(sp.Signature) > 0
}

Try / catch

if err := checker.CheckPolicy(channelID, policyName, signedProp); err != nil {
    if strings.HasPrefix(err.Error(), "Invalid signed proposal during check policy") {
        // reconstruct SignedProposal from the inbound request before retrying
    }
    return err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04). Data as JSON: /api/errors/547d86266296b740. Report an issue: GitHub.