hyperledger/fabric · error
no endorsements
Error message
no endorsements
What it means
After deduplicating endorsers, CreateSignedTx requires at least one endorsement to place in the ChaincodeEndorsedAction. Since responses were already required non-empty, this fires in the degenerate case where the collected endorsement set ends up empty.
Source
Thrown at protoutil/txutils.go:212
}
// fill endorsements according to their uniqueness
endorsersUsed := make(map[string]struct{})
var endorsements []*peer.Endorsement
for _, r := range resps {
if r.Endorsement == nil {
continue
}
key := string(r.Endorsement.Endorser)
if _, used := endorsersUsed[key]; used {
continue
}
endorsements = append(endorsements, r.Endorsement)
endorsersUsed[key] = struct{}{}
}
if len(endorsements) == 0 {
return nil, errors.Errorf("no endorsements")
}
// create ChaincodeEndorsedAction
cea := &peer.ChaincodeEndorsedAction{ProposalResponsePayload: resps[0].Payload, Endorsements: endorsements}
// obtain the bytes of the proposal payload that will go to the transaction
propPayloadBytes, err := GetBytesProposalPayloadForTx(pPayl)
if err != nil {
return nil, err
}
// serialize the chaincode action payload
cap := &peer.ChaincodeActionPayload{ChaincodeProposalPayload: propPayloadBytes, Action: cea}
capBytes, err := GetBytesChaincodeActionPayload(cap)
if err != nil {
return nil, err
}
View on GitHub (pinned to 2736b63f8f)
Solutions
- Ensure each ProposalResponse passed in carries a valid Endorsement (signed by an endorser)
- Use responses returned directly by the endorser service instead of hand-built ones
- In tests, generate responses via a helper that populates Endorsement
- If no endorsements can be obtained, fail before attempting to build the tx
Example fix
// before
resp := &peer.ProposalResponse{Response: &peer.Response{Status: 200}} // no Endorsement
env, err := protoutil.CreateSignedTx(proposal, signer, resp)
// after
resp, err := endorser.ProcessProposal(ctx, signedProp)
if err != nil || resp == nil || resp.Endorsement == nil {
return nil, fmt.Errorf("no endorsement: %w", err)
}
env, err := protoutil.CreateSignedTx(proposal, signer, resp) Defensive patterns
Strategy: validation
Validate before calling
func hasEndorsement(r *peer.ProposalResponse) error {
if r == nil || r.Endorsement == nil {
return fmt.Errorf("response missing endorsement")
}
return nil
} Type guard
func isEndorsed(r *peer.ProposalResponse) bool {
return r != nil && r.Endorsement != nil
} Try / catch
for _, r := range resps {
if err := hasEndorsement(r); err != nil {
return nil, err
}
}
tx, err := protoutil.CreateSignedTx(proposal, signer, resps...) Prevention
- Use responses returned by the endorser service, not hand-built structs
- Verify Endorsement is populated when constructing test fixtures
- Drop responses with nil endorsements before assembly and report why
When it happens
Trigger: Calling CreateSignedTx with responses whose Endorsement fields are all nil/empty so that no endorsements accumulate, or an effectively empty deduplicated endorsement set.
Common situations: Manually constructed or partially deserialized ProposalResponse objects missing Endorsement; responses built in tests without running real endorsement; upstream code stripping endorsements.
Related errors
- at least one proposal response is required
- failed to execute transaction %s
- timeout expired while executing transaction
- chaincode definition for '%s' exists, but chaincode is not i
- could not get channel config for channel '%s'
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/2520f7bc6dc1fe7d.
Report an issue: GitHub.