hyperledger/fabric · error

response payload is missing extension

Error message

response payload is missing extension

What it means

After unmarshaling the ProposalResponsePayload, GetPayloads expects Extension to hold the marshaled ChaincodeAction (results/events). A nil Extension means the endorsement response had no chaincode action attached, so the function reports the missing extension.

Source

Thrown at protoutil/txutils.go:38

// GetPayloads gets the underlying payload objects in a TransactionAction
func GetPayloads(txActions *peer.TransactionAction) (*peer.ChaincodeActionPayload, *peer.ChaincodeAction, error) {
	// TODO: pass in the tx type (in what follows we're assuming the
	// type is ENDORSER_TRANSACTION)
	ccPayload, err := UnmarshalChaincodeActionPayload(txActions.Payload)
	if err != nil {
		return nil, nil, err
	}

	if ccPayload.Action == nil || ccPayload.Action.ProposalResponsePayload == nil {
		return nil, nil, errors.New("no payload in ChaincodeActionPayload")
	}
	pRespPayload, err := UnmarshalProposalResponsePayload(ccPayload.Action.ProposalResponsePayload)
	if err != nil {
		return nil, nil, err
	}

	if pRespPayload.Extension == nil {
		return nil, nil, errors.New("response payload is missing extension")
	}

	respPayload, err := UnmarshalChaincodeAction(pRespPayload.Extension)
	if err != nil {
		return ccPayload, nil, err
	}
	return ccPayload, respPayload, nil
}

// GetEnvelopeFromBlock gets an envelope from a block's Data field.
func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error) {
	// Block always begins with an envelope
	var err error
	env := &common.Envelope{}
	if err = proto.Unmarshal(data, env); err != nil {
		return nil, errors.Wrap(err, "error unmarshalling Envelope")
	}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure endorsers populate ProposalResponsePayload.Extension with a marshaled ChaincodeAction (default fabric endorser path does this).
  2. When constructing responses in tests/tools, marshal a ChaincodeAction into Extension.
  3. Guard pRespPayload.Extension != nil before calling GetPayloads in block/event walkers and skip such transactions.
  4. Verify block integrity — corruption can drop trailing fields like Extension.

Example fix

// before
respPayload := &peer.ProposalResponsePayload{ProposalHash: hash}

// after
action := &peer.ChaincodeAction{Results: results, Events: events}
respPayload := &peer.ProposalResponsePayload{
    ProposalHash: hash,
    Extension:    protoutil.MarshalOrPanic(action),
}
Defensive patterns

Strategy: validation

Validate before calling

pRespPayload, err := protoutil.UnmarshalProposalResponsePayload(ccPayload.Action.ProposalResponsePayload)
if err != nil {
    return err
}
if pRespPayload.Extension == nil {
    return errors.New("proposal response has no ChaincodeAction extension; skipping")
}

Type guard

func hasActionExtension(p *peer.ProposalResponsePayload) bool {
    return p != nil && p.Extension != nil
}

Try / catch

res, ev, err := protoutil.GetPayloads(txActions)
if err != nil {
    if strings.Contains(err.Error(), "response payload is missing extension") {
        return nil // endorser returned no chaincode action; skip
    }
    return err
}

Prevention

When it happens

Trigger: GetPayloads encounters a ProposalResponsePayload whose Extension field is nil — an endorser produced a response without the ChaincodeAction extension, or the payload bytes were corrupted/truncated so the extension was lost.

Common situations: Chaincode invocation that panicked/failed on the endorser yielding a bare response; custom endorsement code building ProposalResponsePayload without Extension; event-processing tools reading malformed proposal responses from blocks.

Related errors


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