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
- Always pass both the SignedProposal and its Proposal together from the caller.
- If the call is intentionally proposal-less (system chaincode path), pass nil for BOTH prop and signedProp.
- Fix proposal parsing on the caller side so signedProp is extracted alongside prop.
- 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
- Always construct Proposals via SDK helpers that yield both prop and signedProp.
- Never hand-build proposals for production transactions.
- Audit custom/test call sites of handler execute for proposal consistency.
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
- First message needs to be a register
- TLS is active but chaincode %s didn't send certificate
- Chaincode %s with given certificate hash %v not found in reg
- Chaincode %s with given certificate hash %v belongs to a dif
- Recv() error: %v, closing connection
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/aa72c599cc7001fc.
Report an issue: GitHub.