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
- Read the wrapped cause to identify whether signing or marshaling failed
- Check that the MSP directory contains a valid keystore (private key) and signcerts for the identity
- Re-enroll or re-register the client identity if certificates are expired/revoked
- 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
- Re-enroll identities before certificates expire
- Keep keystore/signcerts pairs together in one MSP directory
- chmod 600 private keys and ensure the CLI user can read them
- Test signing with a simple `peer channel list` before longer workflows
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
- cannot create proposal, due to %s
- Cannot create signed proposal, due to %s
- signing failed
- could not create a signed Deliver SeekInfo message, somethin
- error converting policy with reference '%s' on channel '%s'
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/5ebb56611db22548.
Report an issue: GitHub.