{"record":{"id":"edd2991d6f33599a","repo":"hyperledger/fabric","slug":"at-least-one-proposal-response-is-required","errorCode":null,"errorMessage":"at least one proposal response is required","messagePattern":"at least one proposal response is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"protoutil/txutils.go","lineNumber":144,"sourceCode":"}\n\n// Signer is the interface needed to sign a transaction\ntype Signer interface {\n\tSign(msg []byte) ([]byte, error)\n\tSerialize() ([]byte, error)\n}\n\n// CreateSignedTx assembles an Envelope message from proposal, endorsements,\n// and a signer. This function should be called by a client when it has\n// collected enough endorsements for a proposal to create a transaction and\n// submit it to peers for ordering\nfunc CreateSignedTx(\n\tproposal *peer.Proposal,\n\tsigner Signer,\n\tresps ...*peer.ProposalResponse,\n) (*common.Envelope, error) {\n\tif len(resps) == 0 {\n\t\treturn nil, errors.New(\"at least one proposal response is required\")\n\t}\n\n\tif signer == nil {\n\t\treturn nil, errors.New(\"signer is required when creating a signed transaction\")\n\t}\n\n\t// the original header\n\thdr, err := UnmarshalHeader(proposal.Header)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\t// the original payload\n\tpPayl, err := UnmarshalChaincodeProposalPayload(proposal.Payload)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/protoutil/txutils.go#L126-L162","documentation":"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.","triggerScenarios":"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...).","commonSituations":"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.","solutions":["Collect at least one successful ProposalResponse from the endorsers before calling CreateSignedTx","Check endorser connectivity/errors when the responses slice is empty and surface that root cause","For multi-endorsement policies, gather responses meeting the policy instead of attempting with none","Spread slices with resps... rather than passing the slice itself"],"exampleFix":"// before\nenv, err := protoutil.CreateSignedTx(proposal, signer) // no responses\n// after\nif len(resps) == 0 {\n    return nil, fmt.Errorf(\"no endorsement responses collected: %w\", collectErr)\n}\nenv, err := protoutil.CreateSignedTx(proposal, signer, resps...)","handlingStrategy":"validation","validationCode":"func requireResponses(resps []*peer.ProposalResponse) error {\n    if len(resps) == 0 {\n        return fmt.Errorf(\"no proposal responses: check endorser errors\")\n    }\n    return nil\n}","typeGuard":"func hasEndorsements(resps []*peer.ProposalResponse) bool {\n    return len(resps) > 0\n}","tryCatchPattern":"if err := requireResponses(resps); err != nil {\n    return nil, err\n}\ntx, err := protoutil.CreateSignedTx(proposal, signer, resps...)\nif err != nil {\n    return nil, fmt.Errorf(\"create tx: %w\", err)\n}","preventionTips":["Fail fast when an endorsement round yields zero responses and report the endorser errors","Spread slices with resps... in variadic calls","Track endorser failures so empty response sets are diagnosable"],"tags":["transaction","endorsement","hyperledger-fabric","missing-argument"],"backgroundTag":"missing-endorsement-response","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}