hyperledger/fabric · error

failed getting proposal context. Signed proposal is nil

Error message

failed getting proposal context. Signed proposal is nil

What it means

Returned by Handler.setChaincodeProposal when a proposal is present (prop != nil) but its signed counterpart is nil. The peer cannot attach proposal context to the chaincode message without the SignedProposal, so the message cannot be validated as coming from a real transaction proposal.

Source

Thrown at core/chaincode/handler.go:1460

	var ccresp *pb.ChaincodeMessage
	select {
	case ccresp = <-txctx.ResponseNotifier:
		// response is sent to user or calling chaincode. ChaincodeMessage_ERROR
		// are typically treated as error
	case <-time.After(timeout):
		err = errors.New(ErrorExecutionTimeout)
		h.Metrics.ExecuteTimeouts.With("chaincode", h.chaincodeID).Add(1)
	case <-h.streamDone():
		err = errors.New(ErrorStreamTerminated)
	}

	return ccresp, err
}

func (h *Handler) setChaincodeProposal(signedProp *pb.SignedProposal, prop *pb.Proposal, msg *pb.ChaincodeMessage) error {
	if prop != nil && signedProp == nil {
		return errors.New("failed getting proposal context. Signed proposal is nil")
	}
	// TODO: This doesn't make a lot of sense. Feels like both are required or
	// neither should be set. Check with a knowledgeable expert.
	if prop != nil {
		msg.Proposal = signedProp
	}
	return nil
}

func (h *Handler) getCollectionStore(channelID string) privdata.CollectionStore {
	return privdata.NewSimpleCollectionStore(
		h.LedgerGetter.GetLedger(channelID),
		h.DeployedCCInfoProvider,
		h.IDDeserializerFactory,
	)
}

func (h *Handler) State() State {

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Always pass both the SignedProposal and its Proposal together from the caller.
  2. If the call is intentionally proposal-less (system chaincode path), pass nil for BOTH prop and signedProp.
  3. Fix proposal parsing on the caller side so signedProp is extracted alongside prop.
  4. In tests, use the standard helpers to build both proposal and signed proposal.

Example fix

// before
h.setChaincodeProposal(nil, prop, msg)
// after
h.setChaincodeProposal(signedProp, prop, msg) // pass the matching signed proposal
Defensive patterns

Strategy: validation

Validate before calling

// caller must supply proposal pairs together
if (prop == nil) != (signedProp == nil) {
    return errors.New("proposal and signed proposal must both be set or both nil")
}

Type guard

func proposalPairValid(signedProp *pb.SignedProposal, prop *pb.Proposal) bool {
    return (prop == nil) == (signedProp == nil)
}

Prevention

When it happens

Trigger: setChaincodeProposal is called with a non-nil prop and nil signedProp while building a ChaincodeMessage — an inconsistent proposal pair passed into the handler's execute path.

Common situations: Custom code or tests calling handler execute with only a Proposal (no SignedProposal); mismatched proposal extraction from a client submission; fabric-sdk or caller constructing proposals manually and dropping the signature envelope.

Related errors


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