{"record":{"id":"645780af16db3333","repo":"hyperledger/fabric","slug":"proto-marshal-called-with-nil-645780","errorCode":null,"errorMessage":"proto: Marshal called with nil","messagePattern":"proto: Marshal called with nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"orderer/consensus/smartbft/util.go","lineNumber":182,"sourceCode":"\n\tif err := ri.ValidateIdentityStructure(sID); err != nil {\n\t\treturn types.RequestInfo{}, err\n\t}\n\n\tvar preimage []byte\n\tpreimage = append(preimage, sigHdr.Nonce...)\n\tpreimage = append(preimage, sigHdr.Creator...)\n\ttxID := sha256.Sum256(preimage)\n\tclientID := sha256.Sum256(sigHdr.Creator)\n\treturn types.RequestInfo{\n\t\tID:       hex.EncodeToString(txID[:]),\n\t\tClientID: hex.EncodeToString(clientID[:]),\n\t}, nil\n}\n\nfunc (ri *RequestInspector) requestIDFromEnvelope(envelope *cb.Envelope) (types.RequestInfo, error) {\n\tif envelope == nil {\n\t\treturn types.RequestInfo{}, errors.New(\"proto: Marshal called with nil\")\n\t}\n\tdata, err := proto.Marshal(envelope)\n\tif err != nil {\n\t\treturn types.RequestInfo{}, err\n\t}\n\n\treq, err := ri.unwrapReqFromEnvelop(envelope)\n\tif err != nil {\n\t\treturn types.RequestInfo{}, err\n\t}\n\n\ttxID := sha256.Sum256(data)\n\tclientID := sha256.Sum256(req.sigHdr.Creator)\n\treturn types.RequestInfo{\n\t\tID:       hex.EncodeToString(txID[:]),\n\t\tClientID: hex.EncodeToString(clientID[:]),\n\t}, nil\n}","sourceCodeStart":164,"sourceCodeEnd":200,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/consensus/smartbft/util.go#L164-L200","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure CONFIG requests carry a valid ConfigEnvelope.LastUpdate (built with protoutil.CreateSignedEnvelope with HeaderType_CONFIG) before submitting","Rebuild the config update with configtxlator/configtxgen so LastUpdate is populated","Check the caller's log 'can't get request ID' and inspect the envelope payload with configtxlator decode to see if LastUpdate is missing","For defense in code, verify the envelope is non-nil and its header type is CONFIG before handing raw requests to the RequestInspector"],"exampleFix":"// before: passing a config envelope without LastUpdate\nreqInfo := ri.RequestID(configTxBytes) // LastUpdate == nil -> error\n// after: build the config update with a populated LastUpdate\nenv, _ := protoutil.CreateSignedEnvelope(cb.HeaderType_CONFIG, channelID, signer, configUpdateEnvelope, 0, 0)\nreqInfo := ri.RequestID([]byte{})\n_ = env","handlingStrategy":"validation","validationCode":"func validConfigRequest(env *cb.Envelope) bool {\n    if env == nil || len(env.Payload) == 0 {\n        return false\n    }\n    p := &cb.Payload{}\n    if proto.Unmarshal(env.Payload, p) != nil || p.Header == nil {\n        return false\n    }\n    chdr, err := protoutil.UnmarshalChannelHeader(p.Header.ChannelHeader)\n    return err == nil && chdr.Type == int32(cb.HeaderType_CONFIG)\n}","typeGuard":"func isEnvelope(env *cb.Envelope) bool { return env != nil && len(env.Payload) > 0 }","tryCatchPattern":null,"preventionTips":["Always build CONFIG transactions with protoutil.CreateSignedEnvelope so LastUpdate is populated","Log RequestID failures (requestInfo empty) at the submission boundary to catch nil envelopes early","Never pass configEnvelope.LastUpdate directly without checking for nil"],"tags":["hyperledger-fabric","smartbft","protobuf","nil-envelope","config-transaction"],"backgroundTag":"nil-protobuf-message","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}