{"record":{"id":"5843d0fbb2ad4f89","repo":"nats-io/nats-server","slug":"mqtt-consumer-replicas-v-cannot-be-higher-than","errorCode":null,"errorMessage":"mqtt: consumer_replicas (%v) cannot be higher than stream_replicas (%v)","messagePattern":"mqtt: consumer_replicas \\((.+?)\\) cannot be higher than stream_replicas \\((.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":742,"sourceCode":"\tif mo.AckWait < 0 {\n\t\treturn errMQTTAckWaitMustBePositive\n\t}\n\tif mo.JSAPITimeout < 0 {\n\t\treturn errMQTTJSAPITimeoutMustBePositive\n\t}\n\t// If strictly standalone and there is no JS enabled, then it won't work...\n\t// For leafnodes, we could either have remote(s) and it would be ok, or no\n\t// remote but accept from a remote side that has \"hub\" property set, which\n\t// then would ok too. So we fail only if we have no leafnode config at all.\n\tif !o.JetStream && o.Cluster.Port == 0 && o.Gateway.Port == 0 &&\n\t\to.LeafNode.Port == 0 && len(o.LeafNode.Remotes) == 0 {\n\t\treturn errMQTTStandaloneNeedsJetStream\n\t}\n\tif err := validatePinnedCerts(mo.TLSPinnedCerts); err != nil {\n\t\treturn fmt.Errorf(\"mqtt: %v\", err)\n\t}\n\tif mo.ConsumerReplicas > 0 && mo.StreamReplicas > 0 && mo.ConsumerReplicas > mo.StreamReplicas {\n\t\treturn fmt.Errorf(\"mqtt: consumer_replicas (%v) cannot be higher than stream_replicas (%v)\",\n\t\t\tmo.ConsumerReplicas, mo.StreamReplicas)\n\t}\n\treturn nil\n}\n\n// Returns true if this connection is from a MQTT client.\n// Lock held on entry.\nfunc (c *client) isMqtt() bool {\n\treturn c.mqtt != nil\n}\n\n// If this is an MQTT client, returns the session client ID,\n// otherwise returns the empty string.\n// Lock held on entry\nfunc (c *client) getMQTTClientID() string {\n\tif !c.isMqtt() {\n\t\treturn _EMPTY_\n\t}","sourceCodeStart":724,"sourceCodeEnd":760,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L724-L760","documentation":"MQTT option validation requires the MQTT consumer's replica count to not exceed its backing stream's replica count; the consumer cannot have more replicas than the stream it reads from. Config with consumer_replicas > stream_replicas (both > 0) is rejected at startup.","triggerScenarios":"Setting mqtt { consumer_replicas: 3, stream_replicas: 1 } (or similar) in the server config; calling ValidateMqttOpts on Options where MqttConsumerReplicas > MqttStreamReplicas > 0.","commonSituations":"Tuning MQTT durability by raising consumer_replicas without also raising stream_replicas; copying HA settings from other JetStream configs where consumer/stream roles differ.","solutions":["Raise stream_replicas to be >= consumer_replicas (e.g. both 3)","Lower consumer_replicas to match stream_replicas","Set one (or both) to 0 to use the server's defaults, which are always consistent"],"exampleFix":"// before (nats-server.conf)\nmqtt {\n  consumer_replicas: 3\n  stream_replicas: 1\n}\n// after\nmqtt {\n  consumer_replicas: 3\n  stream_replicas: 3\n}","handlingStrategy":"validation","validationCode":"func validMqttReplicas(cr, sr int) bool {\n\treturn cr <= 0 || sr <= 0 || cr <= sr\n}\n// reject configs where consumer_replicas > stream_replicas before load","typeGuard":null,"tryCatchPattern":"if err := srv.ValidateMqttOpts(); err != nil {\n\tif strings.Contains(err.Error(), \"cannot be higher than\") {\n\t\treturn fmt.Errorf(\"fix mqtt replica settings: %v\", err)\n\t}\n\treturn err\n}","preventionTips":["Treat stream_replicas as the ceiling; derive consumer_replicas from it","Set both replicas together when editing mqtt HA settings","Validate MQTT config in CI by parsing options before deployment"],"tags":["mqtt","jetstream","configuration"],"backgroundTag":"invalid-replica-configuration","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}