hyperledger/fabric · error

at least one proposal response is required

Error message

at least one proposal response is required

What it means

CreateSignedTx requires at least one endorsed *peer.ProposalResponse to assemble a transaction envelope. Called with zero variadic resps, it returns this error because a transaction cannot be built without an endorsement to attach.

Source

Thrown at protoutil/txutils.go:144

}

// Signer is the interface needed to sign a transaction
type Signer interface {
	Sign(msg []byte) ([]byte, error)
	Serialize() ([]byte, error)
}

// CreateSignedTx assembles an Envelope message from proposal, endorsements,
// and a signer. This function should be called by a client when it has
// collected enough endorsements for a proposal to create a transaction and
// submit it to peers for ordering
func CreateSignedTx(
	proposal *peer.Proposal,
	signer Signer,
	resps ...*peer.ProposalResponse,
) (*common.Envelope, error) {
	if len(resps) == 0 {
		return nil, errors.New("at least one proposal response is required")
	}

	if signer == nil {
		return nil, errors.New("signer is required when creating a signed transaction")
	}

	// the original header
	hdr, err := UnmarshalHeader(proposal.Header)
	if err != nil {
		return nil, err
	}

	// the original payload
	pPayl, err := UnmarshalChaincodeProposalPayload(proposal.Payload)
	if err != nil {
		return nil, err
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Collect at least one successful ProposalResponse from the endorsers before calling CreateSignedTx
  2. Check endorser connectivity/errors when the responses slice is empty and surface that root cause
  3. For multi-endorsement policies, gather responses meeting the policy instead of attempting with none
  4. Spread slices with resps... rather than passing the slice itself

Example fix

// before
env, err := protoutil.CreateSignedTx(proposal, signer) // no responses
// after
if len(resps) == 0 {
    return nil, fmt.Errorf("no endorsement responses collected: %w", collectErr)
}
env, err := protoutil.CreateSignedTx(proposal, signer, resps...)
Defensive patterns

Strategy: validation

Validate before calling

func requireResponses(resps []*peer.ProposalResponse) error {
    if len(resps) == 0 {
        return fmt.Errorf("no proposal responses: check endorser errors")
    }
    return nil
}

Type guard

func hasEndorsements(resps []*peer.ProposalResponse) bool {
    return len(resps) > 0
}

Try / catch

if err := requireResponses(resps); err != nil {
    return nil, err
}
tx, err := protoutil.CreateSignedTx(proposal, signer, resps...)
if err != nil {
    return nil, fmt.Errorf("create tx: %w", err)
}

Prevention

When it happens

Trigger: Calling CreateSignedTx(proposal, signer) with no variadic arguments, or with a slice of responses spread incorrectly (e.g. passing a nil slice rather than resps...).

Common situations: An endorsement round that returned zero responses (all endorsers failed/timed out) and the caller proceeds to assemble the tx anyway; SDK code that drops failed responses and ends up with an empty list.

Related errors


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