hyperledger/fabric · error

error marshaling ChaincodeProposalPayload

Error message

error marshaling ChaincodeProposalPayload

What it means

The ChaincodeProposalPayload (marshaled invocation input + transient map) is serialized inside CreateChaincodeProposalWithTxIDNonceAndTransient; any proto.Marshal error is wrapped with this message. Practically it signals proto library/descriptor incompatibility or invalid input structure.

Source

Thrown at protoutil/proputils.go:76

// CreateChaincodeProposalWithTxIDNonceAndTransient creates a proposal from
// given input
func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.HeaderType, channelID string, cis *peer.ChaincodeInvocationSpec, nonce, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) {
	ccHdrExt := &peer.ChaincodeHeaderExtension{ChaincodeId: cis.ChaincodeSpec.ChaincodeId}
	ccHdrExtBytes, err := proto.Marshal(ccHdrExt)
	if err != nil {
		return nil, "", errors.Wrap(err, "error marshaling ChaincodeHeaderExtension")
	}

	cisBytes, err := proto.Marshal(cis)
	if err != nil {
		return nil, "", errors.Wrap(err, "error marshaling ChaincodeInvocationSpec")
	}

	ccPropPayload := &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap}
	ccPropPayloadBytes, err := proto.Marshal(ccPropPayload)
	if err != nil {
		return nil, "", errors.Wrap(err, "error marshaling ChaincodeProposalPayload")
	}

	// TODO: epoch is now set to zero. This must be changed once we
	// get a more appropriate mechanism to handle it in.
	var epoch uint64

	hdr := &common.Header{
		ChannelHeader: MarshalOrPanic(
			&common.ChannelHeader{
				Type:      int32(typ),
				TxId:      txid,
				Timestamp: timestamppb.Now(),
				ChannelId: channelID,
				Extension: ccHdrExtBytes,
				Epoch:     epoch,
			},
		),
		SignatureHeader: MarshalOrPanic(

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Reconcile fabric-protos-go and fabric versions (go mod tidy, single version per module graph)
  2. Rebuild the binary after `go clean -cache` to clear stale compiled proto descriptors
  3. Validate transient map keys are strings with []byte values (they are by type, so mostly inspect proto version)
Defensive patterns

Strategy: validation

Validate before calling

cpp := &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap}
if _, err := proto.Marshal(cpp); err != nil {
	return fmt.Errorf("proposal payload not marshalable (check proto runtime alignment): %w", err)
}

Type guard

func payloadMarshalable(cpp *peer.ChaincodeProposalPayload) bool {
	if cpp == nil { return false }
	_, err := proto.Marshal(cpp)
	return err == nil
}

Try / catch

proposal, txid, err := protoutil.CreateChaincodeProposalWithTxIDAndTransient(txid, htype, ch, cis, creator, transient)
if err != nil {
	if strings.Contains(err.Error(), "marshaling") {
		return fmt.Errorf("proto incompatibility suspected: %w", err)
	}
	return err
}

Prevention

When it happens

Trigger: Any wrapper call (CreateChaincodeProposalWithTransient, CreateChaincodeProposalWithTxIDAndTransient, CreateProposalFromCISAndTxid, ConstructSignedTxEnv) where marshaling &peer.ChaincodeProposalPayload{Input: cisBytes, TransientMap: transientMap} fails — only realistic with mismatched protobuf descriptors or a corrupted proto registry.

Common situations: Mixed fabric / fabric-protos-go versions in one binary; custom builds of protos; very large transient maps are NOT a cause (proto.Marshal has no size limit here) but corrupt keys could break expectations downstream.

Related errors


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