hyperledger/fabric · error

message is neither a Submit nor a Consensus request

Error message

message is neither a Submit nor a Consensus request

What it means

The cluster Step service's handleMessage expects every incoming request on the stream to be either a SubmitRequest (forwarded transactions) or a ConsensusRequest (Raft messages); anything else produces this error and aborts handling. It guards the Step RPC against malformed or unsupported message types.

Source

Thrown at orderer/common/cluster/service.go:98

		return err
	}

	exp.checkExpiration(time.Now(), extractChannel(request))

	if s.StepLogger.IsEnabledFor(zap.DebugLevel) {
		nodeName := commonNameFromContext(stream.Context())
		s.StepLogger.Debugf("Received message from %s(%s): %v", nodeName, addr, requestAsString(request))
	}

	if submitReq := request.GetSubmitRequest(); submitReq != nil {
		nodeName := commonNameFromContext(stream.Context())
		s.Logger.Debugf("Received message from %s(%s): %v", nodeName, addr, requestAsString(request))
		return s.handleSubmit(submitReq, stream, addr)
	} else if consensusReq := request.GetConsensusRequest(); consensusReq != nil {
		return s.Dispatcher.DispatchConsensus(stream.Context(), request.GetConsensusRequest())
	}

	return errors.Errorf("message is neither a Submit nor a Consensus request")
}

func (s *Service) handleSubmit(request *orderer.SubmitRequest, stream StepStream, addr string) error {
	err := s.Dispatcher.DispatchSubmit(stream.Context(), request)
	if err != nil {
		s.Logger.Warningf("Handling of Submit() from %s failed: %v", addr, err)
		return err
	}
	return err
}

func (s *Service) initializeExpirationCheck(stream orderer.Cluster_StepServer, endpoint, nodeName string) *certificateExpirationCheck {
	return &certificateExpirationCheck{
		minimumExpirationWarningInterval: s.MinimumExpirationWarningInterval,
		expirationWarningThreshold:       s.CertExpWarningThreshold,
		expiresAt:                        expiresAt(stream),
		endpoint:                         endpoint,
		nodeName:                         nodeName,

View on GitHub (pinned to 2736b63f8f)

Solutions

  1. Ensure all ordering nodes run the same compatible Fabric version
  2. Check what client/peer is sending the malformed Step requests in the logs (addr is logged) and fix or upgrade it
  3. Verify no intermediate proxy is corrupting or rewriting gRPC streams
  4. Confirm applications use Broadcast/Deliver APIs, not raw Step, for transaction submission
Defensive patterns

Strategy: validation

Validate before calling

switch {
case req.GetSubmitRequest() != nil: // Submit path
case req.GetConsensusRequest() != nil: // Consensus path
default:
    return errors.New("message is neither a Submit nor a Consensus request")
}

Type guard

func isKnownClusterRequest(req *orderer.Request) bool {
    return req.GetSubmitRequest() != nil || req.GetConsensusRequest() != nil
}

Try / catch

err := service.Step(stream, request)
if err != nil && strings.Contains(err.Error(), "neither a Submit nor a Consensus request") {
    // sender sends unsupported type: log addr, drop or close stream
    return stream.Close()
}

Prevention

When it happens

Trigger: A client sends a StepRequest whose inner request has neither SubmitRequest nor ConsensusRequest populated; a Fabric client of a different version sends an unexpected message type over the cluster Step stream.

Common situations: Fabric version incompatibility between ordering nodes (new message types unknown to the receiver); a misbehaving or buggy custom client calling Step directly; corrupted gRPC payloads after proxy/LB interference with streaming.

Related errors


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