hyperledger/fabric · error

error marshaling ProposalResponse: proto: Marshal called wit

Error message

error marshaling ProposalResponse: proto: Marshal called with nil

What it means

GetBytesProposalResponse serializes a *peer.ProposalResponse. A nil pointer cannot be passed to proto.Marshal, so the function returns this explicit 'proto: Marshal called with nil' error. It protects callers in the transaction-assembly path from opaque proto failures.

Source

Thrown at protoutil/proputils.go:174

	}
	eventBytes, err := proto.Marshal(event)
	return eventBytes, errors.Wrap(err, "error marshaling ChaincodeEvent")
}

// GetBytesChaincodeActionPayload get the bytes of ChaincodeActionPayload from
// the message
func GetBytesChaincodeActionPayload(cap *peer.ChaincodeActionPayload) ([]byte, error) {
	if cap == nil {
		return nil, errors.New("error marshaling ChaincodeActionPayload: proto: Marshal called with nil")
	}
	capBytes, err := proto.Marshal(cap)
	return capBytes, errors.Wrap(err, "error marshaling ChaincodeActionPayload")
}

// GetBytesProposalResponse gets proposal bytes response
func GetBytesProposalResponse(pr *peer.ProposalResponse) ([]byte, error) {
	if pr == nil {
		return nil, errors.New("error marshaling ProposalResponse: proto: Marshal called with nil")
	}
	respBytes, err := proto.Marshal(pr)
	return respBytes, errors.Wrap(err, "error marshaling ProposalResponse")
}

// GetBytesHeader get the bytes of Header from the message
func GetBytesHeader(hdr *common.Header) ([]byte, error) {
	if hdr == nil {
		return nil, errors.New("error marshaling Header: proto: Marshal called with nil")
	}
	bytes, err := proto.Marshal(hdr)
	return bytes, errors.Wrap(err, "error marshaling Header")
}

// GetBytesSignatureHeader get the bytes of SignatureHeader from the message
func GetBytesSignatureHeader(hdr *common.SignatureHeader) ([]byte, error) {
	if hdr == nil {
		return nil, errors.New("error marshaling SignatureHeader: proto: Marshal called with nil")

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Nil-check each ProposalResponse before serialization and drop/log the missing endorsement.
  2. Validate the endorsement collection step so no nil entries enter the slice.
  3. Retry the endorsement against the failed peer before assembling the transaction.
  4. In tests, build &peer.ProposalResponse{...} rather than a nil pointer.

Example fix

// before
prBytes, err := protoutil.GetBytesProposalResponse(pr)
// after
if pr == nil {
    return nil, errors.New("endorsement missing ProposalResponse from peer")
}
prBytes, err := protoutil.GetBytesProposalResponse(pr)
Defensive patterns

Strategy: validation

Validate before calling

for i, pr := range proposalResponses {
    if pr == nil {
        return nil, fmt.Errorf("proposalResponses[%d] is nil: missing endorsement", i)
    }
}

Type guard

func hasProposalResponse(pr *peer.ProposalResponse) bool {
    return pr != nil
}

Try / catch

prBytes, err := protoutil.GetBytesProposalResponse(pr)
if err != nil {
    return nil, errors.Wrap(err, "ProposalResponse serialization failed")
}

Prevention

When it happens

Trigger: Calling protoutil.GetBytesProposalResponse(nil), or passing an element of a ProposalResponse slice that is nil (e.g. a peer in the endorsement set returned no response).

Common situations: Collecting endorsements where one peer's response slot is empty due to a failed/timeout endorsement, or test code (TestProposalResponse) exercising the nil path.

Related errors


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