hyperledger/fabric · error
Message is neither a Submit nor Consensus request
Error message
Message is neither a Submit nor Consensus request
What it means
handleMessage inspects the received clusterRequest's Type. Valid requests are either a Submit request (forwarded to RequestHandler.OnSubmit) or a Consensus request (forwarded to RequestHandler.OnConsensus). Any other message type reaching this point is a protocol violation — the auth envelope carried a message the cluster Step service cannot dispatch — so the stream errors with 'Message is neither a Submit nor Consensus request'.
Source
Thrown at orderer/common/cluster/clusterservice.go:226
exp.checkExpiration(time.Now(), channel)
if tranReq := request.GetNodeTranrequest(); tranReq != nil {
submitReq := &orderer.SubmitRequest{
Channel: channel,
LastValidationSeq: tranReq.LastValidationSeq,
Payload: tranReq.Payload,
}
return s.RequestHandler.OnSubmit(channel, sender, submitReq)
} else if clusterConReq := request.GetNodeConrequest(); clusterConReq != nil {
conReq := &orderer.ConsensusRequest{
Channel: channel,
Payload: clusterConReq.Payload,
Metadata: clusterConReq.Metadata,
}
return s.RequestHandler.OnConsensus(channel, sender, conReq)
}
return errors.Errorf("Message is neither a Submit nor Consensus request")
}
func (s *ClusterService) initializeExpirationCheck(stream orderer.ClusterNodeService_StepServer, endpoint, nodeName string) *certificateExpirationCheck {
expiresAt := time.Time{}
cert := util.ExtractCertificateFromContext(stream.Context())
if cert != nil {
expiresAt = cert.NotAfter
}
return &certificateExpirationCheck{
minimumExpirationWarningInterval: s.MinimumExpirationWarningInterval,
expirationWarningThreshold: s.CertExpWarningThreshold,
expiresAt: expiresAt,
endpoint: endpoint,
nodeName: nodeName,
alert: func(template string, args ...any) {
s.Logger.Warningf(template, args...)
},View on GitHub (pinned to 2736b63f8f)
Solutions
- Align all orderers on the same Fabric version so the Step request types are understood on both ends.
- On the sending side, ensure only cluster.Step requests built via the cluster RPC (Submit via Broadcast-style forwarding, Consensus via etcdraft) are sent to the cluster port — not Deliver/Broadcast envelopes.
- Inspect the incoming message with StepLogger debug to identify the unexpected Type and which sender produced it.
- Check for intermediaries or custom code that re-wraps or re-marshals the StepRequest payload and remove that behavior.
- If a custom client is at fault, regenerate the request using the fabric-protos orderer.ClusterNodeService definitions.
Example fix
// before (custom client sends a Broadcast envelope to the cluster Step endpoint)
req := &orderer.BroadcastRequest{...}
stepClient.Send(req)
// after — send the proper cluster request type
req := &orderer.StepRequest{
Payload: &orderer.StepRequest_SubmitRequest{SubmitRequest: submitReq},
}
stepClient.Send(req) Defensive patterns
Strategy: validation
Validate before calling
// Before dialing the cluster port, assert the request type is dispatchable
switch r := stepReq.Payload.(type) {
case *orderer.StepRequest_SubmitRequest:
// ok
case *orderer.StepRequest_ConsensusRequest:
// ok
default:
return fmt.Errorf("refusing to send unsupported StepRequest payload %T over cluster port", r)
} Type guard
func isDispatchableStepRequest(p *orderer.StepRequest) bool {
switch p.Payload.(type) {
case *orderer.StepRequest_SubmitRequest, *orderer.StepRequest_ConsensusRequest:
return true
}
return false
} Try / catch
if err := handleMessage(...); err != nil && strings.Contains(err.Error(), "neither a Submit nor Consensus") {
log.Printf("unsupported cluster message from %s; dropping stream", addr)
stream.CloseSend()
} Prevention
- Use the same fabric-protos version to build Step requests on both ends
- Point Broadcast/Deliver clients at the standard ports, never at the cluster Step port
- Audit any custom gRPC intermediaries for payload re-marshaling
- Run a two-node test channel after upgrading Fabric versions before a production rollout
When it happens
Trigger: A Step message arrives whose inner clusterRequest type is neither Submit nor Consensus — e.g. a client sends a mis-constructed orderer.StepRequest, an envelope's payload was wrapped/typed incorrectly, or a version-skewed node sends a type this build doesn't recognize.
Common situations: Mixed Fabric versions where the wire format or request types changed; a custom/gRPC client hand-crafting Step messages; corrupted or re-wrapped envelopes produced by intermediate proxies; a sender accidentally using the peer-facing broadcast/deliver payload format against the orderer cluster port.
Related errors
- First message needs to be a register
- got unexpected status: %v -- %s
- request message is nil
- badly formatted message, cannot extract channel
- service stream returned with invalid response type
AI-assisted analysis of hyperledger/fabric@2736b63f8f (2026-09-04).
Data as JSON: /api/errors/f94fb82e6427029b.
Report an issue: GitHub.