hyperledger/fabric · error

error marshaling Transaction: proto: Marshal called with nil

Error message

error marshaling Transaction: proto: Marshal called with nil

What it means

GetBytesTransaction returns 'error marshaling Transaction: proto: Marshal called with nil' when the *peer.Transaction passed to it is nil. proto.Marshal cannot serialize a nil message, so the helper pre-checks and returns this descriptive error instead.

Source

Thrown at protoutil/proputils.go:201

		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")
	}
	bytes, err := proto.Marshal(hdr)
	return bytes, errors.Wrap(err, "error marshaling SignatureHeader")
}

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

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

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

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Verify the Transaction is non-nil before calling GetBytesTransaction
  2. Check upstream GetPayloads results: ensure endorsements produced valid ProposalResponse payloads so the Transaction is built
  3. Add a nil check on tx in createSignedTx/prepareTransaction before serialization

Example fix

// before
txBytes, err := protoutil.GetBytesTransaction(tx) // tx may be nil
// after
if tx == nil {
	return nil, errors.New("transaction is nil; check endorsement responses")
}
txBytes, err := protoutil.GetBytesTransaction(tx)
Defensive patterns

Strategy: validation

Validate before calling

func validTx(tx *peer.Transaction) error {
	if tx == nil {
		return errors.New("Transaction is nil")
	}
	if len(tx.Actions) == 0 {
		return errors.New("Transaction has no actions")
	}
	return nil
}

Type guard

func hasTransaction(tx *peer.Transaction) bool {
	return tx != nil
}

Try / catch

txBytes, err := protoutil.GetBytesTransaction(tx)
if err != nil {
	return nil, fmt.Errorf("cannot serialize transaction: %w", err)
}

Prevention

When it happens

Trigger: Calling protoutil.GetBytesTransaction(nil) directly, or callers createSignedTxTwoActions, prepareTransaction, CreateSignedTx receiving a nil Transaction because payload assembly (e.g. GetPayloads returning nil respPayload) failed upstream.

Common situations: Building signed transactions in SDK/test code where the ChaincodeAction/ProposalResponse failed validation and a nil Transaction was silently propagated to serialization.

Related errors


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