nats-io/nats-server · error
invalid null character in %s %q
Error message
invalid null character in %s %q
What it means
MQTT forbids the NUL character (U+0000) inside topics ([MQTT-4.7.3-2]); the server rejects any topic containing a 0x00 byte even if the bytes are otherwise valid UTF-8. This prevents ambiguous or injection-prone topic names in the subject tree.
Source
Thrown at server/mqtt.go:4332
pp.sz = payloadSize
if pp.sz > 0 {
start = r.pos
r.pos += pp.sz
pp.msg = r.buf[start:r.pos]
} else if pp.sz == 0 {
pp.msg = nil
} else {
return errMQTTInvalidPublishLength
}
return nil
}
func mqttValidateTopic(topic []byte, field string) error {
if !utf8.Valid(topic) {
return fmt.Errorf("invalid utf8 for %s %q", field, topic)
}
if bytes.IndexByte(topic, 0) >= 0 {
return fmt.Errorf("invalid null character in %s %q", field, topic)
}
return nil
}
func mqttValidateString(value string, field string) error {
if !utf8.ValidString(value) {
return fmt.Errorf("invalid utf8 for %s %q", field, value)
}
if strings.IndexByte(value, 0) >= 0 {
return fmt.Errorf("invalid null character in %s %q", field, value)
}
return nil
}
func mqttPubTrace(pp *mqttPublish) string {
dup := pp.flags&mqttPubFlagDup != 0
qos := mqttGetQoS(pp.flags)
retain := mqttIsRetained(pp.flags)View on GitHub (pinned to 3a66a489d2)
Solutions
- Trim or reject NUL bytes from topic strings in the client before publishing/subscribing
- Replace binary data in topics with hex/base64 textual encoding
- Verify the buffer-length calculation doesn't include padding zeros beyond the string
- Escape/strip control characters from user input used to compose topics
Example fix
// before
topic := fmt.Sprintf("devices/%s/events", rawBuf[:cap])
// after
t := strings.TrimRight(string(rawBuf[:n]), "\x00")
if strings.ContainsRune(t, 0) { return errors.New("topic contains NUL") }
topic := fmt.Sprintf("devices/%s/events", t) Defensive patterns
Strategy: validation
Validate before calling
func topicSafe(t string) bool { return !strings.ContainsRune(t, 0) && utf8.ValidString(t) && len(t) > 0 } Type guard
func hasNoNul(b []byte) bool { return bytes.IndexByte(b, 0) < 0 } Try / catch
if err := subscribe(topic); err != nil && strings.Contains(err.Error(), "null character") { topic = strings.ReplaceAll(topic, "\x00", ""); retry() } Prevention
- Trim C-string terminators and buffer padding before using strings as topics
- Encode binary identifiers as hex/base64 instead of raw bytes
- Use length-aware copies, never whole fixed-size buffers
- Add NUL checks in any topic-building utility function
When it happens
Trigger: A client sends a SUBSCRIBE/PUBLISH/UNSUBSCRIBE whose topic contains an embedded 0x00 byte, typically from concatenating C strings, zero-padded buffers, or binary data into the topic.
Common situations: Buffer-based topic construction where leftover zero bytes are included in the length, embedding binary keys/hashes in topics, or templated topics joined with NUL separators by mistake.
Related errors
- character not supported for MQTT topics
- the first packet should be a CONNECT (%v), got %v
- received unknown packet type %d
- invalid fixed header flags %x for packet type %x
- invalid remaining length %d for packet type %x
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/c0fd4b79a917e00c.
Report an issue: GitHub.