{"record":{"id":"3803a9be2b999afd","repo":"nats-io/nats-server","slug":"mqtt-authentication-token-not-compatible-with-pres","errorCode":null,"errorMessage":"mqtt authentication token not compatible with presence of users/nkeys","messagePattern":"mqtt authentication token not compatible with presence of users/nkeys","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":231,"sourceCode":")\n\nvar (\n\tmqttPingResponse     = []byte{mqttPacketPingResp, 0x0}\n\tmqttProtoName        = []byte(\"MQTT\")\n\tmqttOldProtoName     = []byte(\"MQIsdp\")\n\tmqttSessJailDur      = mqttSessFlappingJailDur\n\tmqttFlapCleanItvl    = mqttSessFlappingCleanupInterval\n\tmqttRetainedCacheTTL = mqttDefaultRetainedCacheTTL\n)\n\nvar (\n\terrMQTTNotWebsocketPort           = errors.New(\"MQTT clients over websocket must connect to the Websocket port, not the MQTT port\")\n\terrMQTTTopicFilterCannotBeEmpty   = errors.New(\"topic filter cannot be empty\")\n\terrMQTTMalformedVarInt            = errors.New(\"malformed variable int\")\n\terrMQTTSecondConnectPacket        = errors.New(\"received a second CONNECT packet\")\n\terrMQTTServerNameMustBeSet        = errors.New(\"mqtt requires server name to be explicitly set\")\n\terrMQTTUserMixWithUsersNKeys      = errors.New(\"mqtt authentication username not compatible with presence of users/nkeys\")\n\terrMQTTTokenMixWIthUsersNKeys     = errors.New(\"mqtt authentication token not compatible with presence of users/nkeys\")\n\terrMQTTAckWaitMustBePositive      = errors.New(\"ack wait must be a positive value\")\n\terrMQTTJSAPITimeoutMustBePositive = errors.New(\"JS API timeout must be a positive value\")\n\terrMQTTStandaloneNeedsJetStream   = errors.New(\"mqtt requires JetStream to be enabled if running in standalone mode\")\n\terrMQTTConnFlagReserved           = errors.New(\"connect flags reserved bit not set to 0\")\n\terrMQTTWillAndRetainFlag          = errors.New(\"if Will flag is set to 0, Will Retain flag must be 0 too\")\n\terrMQTTPasswordFlagAndNoUser      = errors.New(\"password flag set but username flag is not\")\n\terrMQTTCIDEmptyNeedsCleanFlag     = errors.New(\"when client ID is empty, clean session flag must be set to 1\")\n\terrMQTTEmptyWillTopic             = errors.New(\"empty Will topic not allowed\")\n\terrMQTTEmptyUsername              = errors.New(\"empty user name not allowed\")\n\terrMQTTTopicIsEmpty               = errors.New(\"topic cannot be empty\")\n\terrMQTTPacketIdentifierIsZero     = errors.New(\"packet identifier cannot be 0\")\n\terrMQTTUnsupportedCharacters      = errors.New(\"character not supported for MQTT topics\")\n\terrMQTTInvalidSession             = errors.New(\"invalid MQTT session\")\n\terrMQTTInvalidRetainFlags         = errors.New(\"invalid retained message flags\")\n\terrMQTTInvalidRetainedMessage     = errors.New(\"invalid retained message\")\n\terrMQTTSessionCollision           = errors.New(\"stored session does not match client ID\")\n\terrMQTTInvalidPublishLength       = errors.New(\"invalid publish message, variable header exceeds remaining length\")\n\terrMQTTAckPipelineStopped         = errors.New(\"QoS1 PUBACK pipeline has shut down while admitting a message, \" +","sourceCodeStart":213,"sourceCodeEnd":249,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L213-L249","documentation":"MQTT inbound authentication can be configured either via a single MQTT-level token (Options.MQTT.Token) or via the server's users/nkeys mechanism, but not both at once. The NATS server rejects Options during validation (server/mqtt.go:721) because combining them creates ambiguous credential precedence for MQTT clients. It is a configuration-time error from ProcessOptions/NewServer, not a runtime client failure.","triggerScenarios":"Setting opts.MQTT.Token to a non-empty string while the Options also define users (opts.Users), an nkey, or an account setup where users/nkeys authentication is present; returned by option validation before the server starts.","commonSituations":"Operators copy an MQTT snippet that sets MQTT.Token into an existing NATS config file that already declares a users block, or migrate from static token auth to users/nkeys without removing the old MQTT.Token entry.","solutions":["Remove the MQTT.Token field from your Options/config and rely on the per-user credentials for MQTT clients.","Alternatively remove the users/nkeys entries so the MQTT-level token is the sole authentication mechanism.","If using a config file, restart after editing and check that only one MQTT auth mechanism is declared."],"exampleFix":"// before\no := &server.Options{MQTT: server.MQTTOpts{Token: \"mytoken\"}}\no.Users = []*server.User{{Username: \"u\", Password: \"p\"}}\n// after\no := &server.Options{MQTT: server.MQTTOpts{}}\no.Users = []*server.User{{Username: \"u\", Password: \"p\"}}","handlingStrategy":"validation","validationCode":"if o.MQTT.Token != \"\" && (len(o.Users) > 0 || o.Nkeys != nil) {\n    return fmt.Errorf(\"remove MQTT.Token: it conflicts with users/nkeys auth\")\n}","typeGuard":null,"tryCatchPattern":"if _, err := server.NewServer(opts); err != nil {\n    if strings.Contains(err.Error(), \"token not compatible\") {\n        // drop MQTT.Token and rebuild options\n    }\n}","preventionTips":["Keep a single auth mechanism per listener; audit config files after merging snippets.","Add a unit test asserting NewServer succeeds with your production Options.","Validate Options in CI before deploying configs."],"tags":["mqtt","config","authentication"],"backgroundTag":"conflicting-auth-config","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}