hyperledger/fabric · error
proposal cannot be nil
Error message
proposal cannot be nil
What it means
signProposal in internal/peer/lifecycle/chaincode/common.go is a shared helper that serializes and signs a proposal before it is sent to the endorser. It refuses to run when the *pb.Proposal argument is nil, returning this error immediately before any marshaling or signing occurs. This indicates an internal construction bug: the caller built no proposal at all.
Source
Thrown at internal/peer/lifecycle/chaincode/common.go:50
Deliver(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverClient, error)
DeliverFiltered(ctx context.Context, opts ...grpc.CallOption) (pb.Deliver_DeliverClient, error)
}
// Signer defines the interface needed for signing messages
type Signer interface {
Sign(msg []byte) ([]byte, error)
Serialize() ([]byte, error)
}
// Writer defines the interface needed for writing a file
type Writer interface {
WriteFile(string, string, []byte) error
}
func signProposal(proposal *pb.Proposal, signer Signer) (*pb.SignedProposal, error) {
// check for nil argument
if proposal == nil {
return nil, errors.New("proposal cannot be nil")
}
if signer == nil {
return nil, errors.New("signer cannot be nil")
}
proposalBytes, err := proto.Marshal(proposal)
if err != nil {
return nil, errors.Wrap(err, "error marshaling proposal")
}
signature, err := signer.Sign(proposalBytes)
if err != nil {
return nil, err
}
return &pb.SignedProposal{
ProposalBytes: proposalBytes,View on GitHub (pinned to 2736b63f8f)
Solutions
- Check upstream proposal construction (createInput/createCommand) for an ignored error that left the proposal nil
- If calling signProposal directly (tests/tools), ensure the pb.Proposal is non-nil before invoking
- Update to a stock fabric release where all callers validate the proposal before signing
Example fix
// before
sp, err := signProposal(nil, signer)
// after
if proposal == nil {
return errors.New("no proposal to sign")
}
sp, err := signProposal(proposal, signer) Defensive patterns
Strategy: validation
Validate before calling
if proposal == nil {
return errors.New("proposal must be constructed before signing")
}
sp, err := signProposal(proposal, signer) Type guard
func hasProposal(p *pb.Proposal) bool { return p != nil } Try / catch
if err := run(); err != nil {
if strings.Contains(err.Error(), "proposal cannot be nil") {
// fix proposal construction upstream
}
} Prevention
- Always build proposals via the library's createInput/createCommand helpers
- Check errors from proposal-construction functions before proceeding
- Add nil assertions in test harnesses that call signProposal directly
When it happens
Trigger: Any of the lifecycle CLI commands (Approve, ReadinessCheck, Commit, Get, Install, Query) calls signProposal with a nil proposal, which happens only when the command's createInput/proposal-construction step failed to produce a proposal yet execution continued.
Common situations: Practically only seen from modified/forked code or test harnesses that invoke signProposal directly with nil; stock CLI commands always build a proposal first.
Related errors
- signer cannot be nil
- query iterator not found
- application config does not exist for channel '%s'
- unknown chaincode '%s' for channel '%s'
- could not find chaincode with package id '%s'
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/abe03105f8853ec4.
Report an issue: GitHub.