{"record":{"id":"aa1e35d010ac9744","repo":"hyperledger/fabric","slug":"request-message-is-nil","errorCode":null,"errorMessage":"request message is nil","messagePattern":"request message is nil","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"orderer/common/cluster/clusterservice.go","lineNumber":193,"sourceCode":"\terr = VerifySignature(fromIdentity, SHA256Digest(msg), authReq.Signature)\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"signature mismatch\")\n\t}\n\n\treturn authReq, nil\n}\n\nfunc (s *ClusterService) handleMessage(stream ClusterStepStream, addr string, exp *certificateExpirationCheck, channel string, sender uint64, streamID uint64) error {\n\trequest, err := stream.Recv()\n\tif err == io.EOF {\n\t\treturn err\n\t}\n\tif err != nil {\n\t\ts.Logger.Warningf(\"Stream read from %s failed: %v\", addr, err)\n\t\treturn err\n\t}\n\tif request == nil {\n\t\treturn errors.Errorf(\"request message is nil\")\n\t}\n\n\ts.Lock.RLock()\n\t_, authorized := s.MembershipByChannel[channel].AuthorizedStreams.Load(streamID)\n\ts.Lock.RUnlock()\n\n\tif !authorized {\n\t\treturn errors.Errorf(\"stream %d is stale\", streamID)\n\t}\n\n\tif s.StepLogger.IsEnabledFor(zap.DebugLevel) {\n\t\tnodeName := commonNameFromContext(stream.Context())\n\t\ts.StepLogger.Debugf(\"Received message from %s(%s): %v\", nodeName, addr, clusterRequestAsString(request))\n\t}\n\n\texp.checkExpiration(time.Now(), channel)\n\n\tif tranReq := request.GetNodeTranrequest(); tranReq != nil {","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/orderer/common/cluster/clusterservice.go#L175-L211","documentation":"handleMessage reads the next request from the ClusterStepStream. If Recv returns no error but the request is nil, the stream handed back an empty message, which is not a valid Submit/Consensus request. The service treats this as a protocol violation and closes the stream with 'request message is nil'.","triggerScenarios":"Step's stream Recv loop obtains err == nil with request == nil — i.e. the remote side sent an empty/void message on the orderer.ClusterNodeService/Step gRPC stream. This can arise from a peer implementation bug, a half-open connection that delivered an empty frame, or a client that opened the stream and sent an empty envelope.","commonSituations":"Network gear or proxies cutting the gRPC stream mid-use leading to empty reads; a non-Fabric or older-version client speaking to the Step endpoint incorrectly; transient connection drops during cluster membership churn causing Recv to surface a nil message with nil error.","solutions":["Retry the Step connection — the sender (Cluster/Dialer) will re-establish the stream automatically; the error propagates and triggers a reconnect with backoff.","Upgrade all orderers to the same Fabric version so the Step stream protocol implementations match.","Check network intermediaries (load balancers, Istio, NAT gateways) for idle-timeout or body-mangling behavior and set keepalives appropriately.","Enable StepLogger debug on both sides to see whether the sender actually transmitted a message before the failure."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := handleMessage(stream, addr, exp, channel, sender, streamID)\nif err != nil && strings.Contains(err.Error(), \"request message is nil\") {\n    // transient/empty frame: tear down and let the dialer reconnect\n    stream.CloseSend()\n    time.Sleep(backoff)\n    return retryStep(channel, endpoint)\n}","preventionTips":["Enable gRPC keepalives on both orderer sides to avoid half-open streams","Keep all orderer nodes on the same Fabric version","Check load balancers/service meshes for idle-timeout stream resets","Monitor Step stream error rates to catch flaky network paths early"],"tags":["hyperledger-fabric","orderer","grpc","stream"],"backgroundTag":"grpc-stream-message-nil","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"}