nats-io/nats-server · error
character not supported for MQTT topics
Error message
character not supported for MQTT topics
What it means
errMQTTUnsupportedCharacters is returned when a topic (or subject) contains characters that are not allowed in MQTT topics. Specific bytes such as 0x7f (DEL, used internally as a SubjectTree pivot marker) and other control/unsupported characters are rejected to keep the subject tree consistent and to prevent control-line splitting when subjects are forwarded to other connection types (e.g. leaf nodes). Thrown from the topic-character validation switch around server/mqtt.go:6234-6240.
Source
Thrown at server/mqtt.go:243
errMQTTNotWebsocketPort = errors.New("MQTT clients over websocket must connect to the Websocket port, not the MQTT port")
errMQTTTopicFilterCannotBeEmpty = errors.New("topic filter cannot be empty")
errMQTTMalformedVarInt = errors.New("malformed variable int")
errMQTTSecondConnectPacket = errors.New("received a second CONNECT packet")
errMQTTServerNameMustBeSet = errors.New("mqtt requires server name to be explicitly set")
errMQTTUserMixWithUsersNKeys = errors.New("mqtt authentication username not compatible with presence of users/nkeys")
errMQTTTokenMixWIthUsersNKeys = errors.New("mqtt authentication token not compatible with presence of users/nkeys")
errMQTTAckWaitMustBePositive = errors.New("ack wait must be a positive value")
errMQTTJSAPITimeoutMustBePositive = errors.New("JS API timeout must be a positive value")
errMQTTStandaloneNeedsJetStream = errors.New("mqtt requires JetStream to be enabled if running in standalone mode")
errMQTTConnFlagReserved = errors.New("connect flags reserved bit not set to 0")
errMQTTWillAndRetainFlag = errors.New("if Will flag is set to 0, Will Retain flag must be 0 too")
errMQTTPasswordFlagAndNoUser = errors.New("password flag set but username flag is not")
errMQTTCIDEmptyNeedsCleanFlag = errors.New("when client ID is empty, clean session flag must be set to 1")
errMQTTEmptyWillTopic = errors.New("empty Will topic not allowed")
errMQTTEmptyUsername = errors.New("empty user name not allowed")
errMQTTTopicIsEmpty = errors.New("topic cannot be empty")
errMQTTPacketIdentifierIsZero = errors.New("packet identifier cannot be 0")
errMQTTUnsupportedCharacters = errors.New("character not supported for MQTT topics")
errMQTTInvalidSession = errors.New("invalid MQTT session")
errMQTTInvalidRetainFlags = errors.New("invalid retained message flags")
errMQTTInvalidRetainedMessage = errors.New("invalid retained message")
errMQTTSessionCollision = errors.New("stored session does not match client ID")
errMQTTInvalidPublishLength = errors.New("invalid publish message, variable header exceeds remaining length")
errMQTTAckPipelineStopped = errors.New("QoS1 PUBACK pipeline has shut down while admitting a message, " +
"abandoning the wait for its JetStream ack; failing the connection, " +
"the client will re-send unacknowledged PUBLISH packets on reconnect")
)
type srvMQTT struct {
listener net.Listener
listenerErr error
authOverride bool
sessmgr mqttSessionManager
}
type mqttSessionManager struct {View on GitHub (pinned to 3a66a489d2)
Solutions
- Sanitize topics before use: strip or replace DEL and control characters, and keep topics to allowed MQTT characters.
- Restrict topic names to [A-Za-z0-9] plus '/', '_', '-' style safe sets in your publish/subscribe call sites.
- Purge or re-publish retained messages stored with unsupported characters.
Example fix
// before nc.Publish(userInput+"/status", data) // after topic := sanitizeTopic(userInput) // remove DEL/control chars, reject empty nc.Publish(topic+"/status", data)
Defensive patterns
Strategy: validation
Validate before calling
func sanitizeTopic(topic string) (string, error) {
for _, r := range topic {
if r == 0x7f || (r < 0x20 && r != '/') {
return "", fmt.Errorf("unsupported character %q in topic", r)
}
}
return topic, nil
} Type guard
func hasOnlySafeTopicChars(topic string) bool {
for _, r := range topic {
if r == 0x7f || (r < 0x20) {
return false
}
}
return len(topic) > 0
} Try / catch
if _, err := sanitizeTopic(topic); err != nil {
log.Warn("rejecting topic with unsupported characters", "topic", topic)
return
} Prevention
- Never build topics from raw binary data or untrusted user input without sanitizing
- Whitelist allowed topic characters instead of blacklisting
- Test retained-message data for control characters when migrating between versions
When it happens
Trigger: Publishing or subscribing to a topic containing DEL (0x7f), other control bytes, or characters forbidden for MQTT topics; retained-message recovery hits such a character and the validation returns the error.
Common situations: Applications interpolating raw binary payloads, filenames, or user input into topic names; topics built from strings containing '\x7f' or newline/control characters; legacy data in a retained-message stream containing unsupported bytes.
Related errors
- invalid utf8 for %s %q
- invalid null character in %s %q
- ErrBadEncoding
- ErrBadVersion
- MQTT clients over websocket must connect to the Websocket po
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/2aba9118a5457328.
Report an issue: GitHub.