hyperledger/fabric · error

cannot create signed proposal, due to %s

Error message

cannot create signed proposal, due to %s

What it means

Returned by joinBySnapshotStatus when signing the proposal fails. After the proposal is built, protoutil.GetSignedProposal signs it with the local signer's private key; any cryptographic or marshaling failure is wrapped here.

Source

Thrown at internal/peer/channel/joinbysnapshotstatus.go:84

	invocation := &pb.ChaincodeInvocationSpec{
		ChaincodeSpec: &pb.ChaincodeSpec{
			Type:        pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]),
			ChaincodeId: &pb.ChaincodeID{Name: "cscc"},
			Input:       &pb.ChaincodeInput{Args: [][]byte{[]byte(cscc.JoinBySnapshotStatus)}},
		},
	}

	var prop *pb.Proposal
	c, _ := cc.cf.Signer.Serialize()
	prop, _, err = protoutil.CreateProposalFromCIS(common2.HeaderType_ENDORSER_TRANSACTION, "", invocation, c)
	if err != nil {
		return nil, fmt.Errorf("cannot create proposal, due to %s", err)
	}

	var signedProp *pb.SignedProposal
	signedProp, err = protoutil.GetSignedProposal(prop, cc.cf.Signer)
	if err != nil {
		return nil, fmt.Errorf("cannot create signed proposal, due to %s", err)
	}

	proposalResp, err := cc.cf.EndorserClient.ProcessProposal(context.Background(), signedProp)
	if err != nil {
		return nil, fmt.Errorf("failed sending proposal, due to %s", err)
	}

	if proposalResp.Response == nil || proposalResp.Response.Status != http.StatusOK {
		return nil, fmt.Errorf("received bad response, status %d: %s", proposalResp.Response.Status, proposalResp.Response.Message)
	}

	joinbysnapshotStatus := &pb.JoinBySnapshotStatus{}
	err = proto.Unmarshal(proposalResp.Response.Payload, joinbysnapshotStatus)
	if err != nil {
		return nil, fmt.Errorf("cannot query joinbysnapshot status, due to %s", err)
	}
	return joinbysnapshotStatus, nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Read the wrapped cause to identify whether signing or marshaling failed
  2. Check that the MSP directory contains a valid keystore (private key) and signcerts for the identity
  3. Re-enroll or re-register the client identity if certificates are expired/revoked
  4. Fix file permissions on the crypto material so the CLI can read the private key

Example fix

// before: empty keystore -> GetSignedProposal fails
// peer channel joinbysnapshot ... --mspdir /path/msp  (keystore empty)
// after: ensure key exists before invoking
if _, err := os.Stat(filepath.Join(mspDir, "keystore")); os.IsNotExist(err) {
    return fmt.Errorf("private key missing in MSP keystore: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: keystore must contain a private key
entries, _ := os.ReadDir(filepath.Join(mspDir, "keystore"))
if len(entries) == 0 { return errors.New("no private key in MSP keystore") }

Try / catch

signedProp, err := protoutil.GetSignedProposal(prop, signer)
if err != nil {
    return nil, fmt.Errorf("cannot create signed proposal, due to %s", err)
}

Prevention

When it happens

Trigger: protoutil.GetSignedProposal(prop, cc.cf.Signer) errors — the signer cannot sign the proposal bytes, typically because the signing identity or its private key is unavailable/invalid.

Common situations: MSP directory missing the keystore/private key; expired or revoked enrollment certificate; wrong --mspdir passed to the peer CLI; crypto material permissions prevent reading the key file.

Related errors


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