nats-io/nats-server · error
topic cannot be empty
Error message
topic cannot be empty
What it means
errMQTTTopicIsEmpty is returned when an MQTT PUBLISH packet is parsed and its topic name has zero length. The MQTT spec requires every PUBLISH to carry a non-empty topic string, so the server rejects the packet at parse time instead of forwarding a message with no destination. It is thrown from mqttParsePub (server/mqtt.go:4264) when len(pp.topic)==0 after decoding the variable header.
Source
Thrown at server/mqtt.go:241
var (
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
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Fix the client so it writes a valid, non-empty topic (length-prefixed) into the PUBLISH variable header before sending.
- Validate the topic string on the publishing side before constructing the packet (e.g. reject empty strings early).
- If you are generating test/protocol bytes, include the topic length prefix plus topic bytes, e.g. []byte{0, 3, 'a', '/', 'b'}.
Example fix
// before: client sends PUBLISH with empty topic
buf := []byte{0x30, remLen, 0x00, 0x00 /* zero-length topic */, payload...}
// after: write a real topic
buf = appendVarInt(buf, len(topic))
buf = append(buf, topic...) Defensive patterns
Strategy: validation
Validate before calling
func validatePublishTopic(topic string) error {
if len(topic) == 0 {
return errors.New("topic cannot be empty")
}
return nil
} Try / catch
if err := client.Publish(topic, payload); err != nil {
if strings.Contains(err.Error(), "topic cannot be empty") {
log.Warn("skipping publish: empty topic")
return
}
return err
} Prevention
- Always assign a non-empty topic constant or configuration value before publishing
- Validate topic strings at the application boundary before building packets
- Add a unit test asserting empty topics are rejected client-side
When it happens
Trigger: A client sends a PUBLISH packet whose variable header encodes a topic of length 0 (two length bytes 0x00 0x00 and no topic bytes); mqttParsePub then returns errMQTTTopicIsEmpty and the packet is rejected.
Common situations: Hand-rolled or buggy MQTT client serialization that forgets to write the topic field; fuzzing or malformed-packet tests against the server; a truncated/corrupted PUBLISH where the topic bytes were dropped; protocol-level test vectors such as the {"empty topic", []byte{0,0}, 2, ...} case in mqtt_test.go.
Related errors
- packet identifier cannot be 0
- MQTT clients over websocket must connect to the Websocket po
- topic filter cannot be empty
- malformed variable int
- received a second CONNECT packet
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/bcc9bfcd454a0fce.
Report an issue: GitHub.