hyperledger/fabric · error

proto: Marshal called with nil

Error message

proto: Marshal called with nil

What it means

RequestInspector.requestIDFromEnvelope rejects a nil *cb.Envelope before calling proto.Marshal, returning the error message 'proto: Marshal called with nil'. The message mimics the proto library's nil-marshal error because marshaling a nil envelope would fail anyway; the guard makes the failure explicit. Callers pass configEnvelope.LastUpdate, which is nil for genesis-style config updates that carry no LastUpdate envelope.

Source

Thrown at orderer/consensus/smartbft/util.go:182

	if err := ri.ValidateIdentityStructure(sID); err != nil {
		return types.RequestInfo{}, err
	}

	var preimage []byte
	preimage = append(preimage, sigHdr.Nonce...)
	preimage = append(preimage, sigHdr.Creator...)
	txID := sha256.Sum256(preimage)
	clientID := sha256.Sum256(sigHdr.Creator)
	return types.RequestInfo{
		ID:       hex.EncodeToString(txID[:]),
		ClientID: hex.EncodeToString(clientID[:]),
	}, nil
}

func (ri *RequestInspector) requestIDFromEnvelope(envelope *cb.Envelope) (types.RequestInfo, error) {
	if envelope == nil {
		return types.RequestInfo{}, errors.New("proto: Marshal called with nil")
	}
	data, err := proto.Marshal(envelope)
	if err != nil {
		return types.RequestInfo{}, err
	}

	req, err := ri.unwrapReqFromEnvelop(envelope)
	if err != nil {
		return types.RequestInfo{}, err
	}

	txID := sha256.Sum256(data)
	clientID := sha256.Sum256(req.sigHdr.Creator)
	return types.RequestInfo{
		ID:       hex.EncodeToString(txID[:]),
		ClientID: hex.EncodeToString(clientID[:]),
	}, nil
}

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure CONFIG requests carry a valid ConfigEnvelope.LastUpdate (built with protoutil.CreateSignedEnvelope with HeaderType_CONFIG) before submitting
  2. Rebuild the config update with configtxlator/configtxgen so LastUpdate is populated
  3. Check the caller's log 'can't get request ID' and inspect the envelope payload with configtxlator decode to see if LastUpdate is missing
  4. For defense in code, verify the envelope is non-nil and its header type is CONFIG before handing raw requests to the RequestInspector

Example fix

// before: passing a config envelope without LastUpdate
reqInfo := ri.RequestID(configTxBytes) // LastUpdate == nil -> error
// after: build the config update with a populated LastUpdate
env, _ := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, signer, configUpdateEnvelope, 0, 0)
reqInfo := ri.RequestID([]byte{})
_ = env
Defensive patterns

Strategy: validation

Validate before calling

func validConfigRequest(env *cb.Envelope) bool {
    if env == nil || len(env.Payload) == 0 {
        return false
    }
    p := &cb.Payload{}
    if proto.Unmarshal(env.Payload, p) != nil || p.Header == nil {
        return false
    }
    chdr, err := protoutil.UnmarshalChannelHeader(p.Header.ChannelHeader)
    return err == nil && chdr.Type == int32(cb.HeaderType_CONFIG)
}

Type guard

func isEnvelope(env *cb.Envelope) bool { return env != nil && len(env.Payload) > 0 }

Prevention

When it happens

Trigger: Calling RequestID on a CONFIG-type request whose inner ConfigEnvelope has LastUpdate == nil (e.g. a genesis/config block submission without a last-update envelope), so requestIDFromEnvelope receives a nil envelope.

Common situations: Submitting or replaying config transactions generated by tooling that leaves LastUpdate unset; replaying blocks from another channel or older network format; unit tests passing nil envelopes into RequestInspector.

Related errors


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