nats-io/nats-server · error
wrong %ssubscribe reserved flags: %x
Error message
wrong %ssubscribe reserved flags: %x
What it means
The SUBSCRIBE and UNSUBSCRIBE packets must have fixed reserved flag bits set to a fixed value per the MQTT spec ([MQTT-3.8.1-1], [MQTT-3.10.1-1]); the server parses the first header byte and rejects any other flag combination. The %s placeholder reads "" (subscribe) or "un" (unsubscribe).
Source
Thrown at server/mqtt.go:5301
//
//////////////////////////////////////////////////////////////////////////////
func (c *client) mqttParseSubs(r *mqttReader, b byte, pl int) (uint16, []*mqttFilter, error) {
return c.mqttParseSubsOrUnsubs(r, b, pl, true)
}
func (c *client) mqttParseSubsOrUnsubs(r *mqttReader, b byte, pl int, sub bool) (uint16, []*mqttFilter, error) {
var expectedFlag byte
var action string
if sub {
expectedFlag = mqttSubscribeFlags
} else {
expectedFlag = mqttUnsubscribeFlags
action = "un"
}
// Spec [MQTT-3.8.1-1], [MQTT-3.10.1-1]
if rf := b & 0xf; rf != expectedFlag {
return 0, nil, fmt.Errorf("wrong %ssubscribe reserved flags: %x", action, rf)
}
pi, err := mqttParsePIPacket(r)
if err != nil {
return 0, nil, err
}
end := r.pos + (pl - 2)
var filters []*mqttFilter
for r.pos < end {
// Don't make a copy now because, this will happen during conversion
// or when processing the sub.
topic, err := r.readBytes("topic filter", false)
if err != nil {
return 0, nil, err
}
if len(topic) == 0 {
return 0, nil, errMQTTTopicFilterCannotBeEmpty
}
// Spec [MQTT-3.8.3-1], [MQTT-3.10.3-1]View on GitHub (pinned to 3a66a489d2)
Solutions
- Set the SUBSCRIBE/UNSUBSCRIBE fixed header correctly: byte = packetType<<4 | 0x02
- Enable TLS to eliminate in-transit byte corruption and retest
- Verify the client library version supports the MQTT version negotiated and upgrade if buggy
- Inspect the raw first header byte with a packet capture to confirm which flags the client sends
Example fix
// before (client-side header) header := byte(subscribeType)<<4 // flags = 0000, wrong // after header := byte(subscribeType)<<4 | 0x02 // reserved flags per spec
Defensive patterns
Strategy: validation
Validate before calling
func subscribeHeader(packetType byte) byte { return packetType<<4 | 0x02 } // required reserved flags for SUB/UNSUB Type guard
func hasValidSubscribeFlags(b byte) bool { return b&0x0f == 0x02 } Try / catch
if err := subscribe(topic); err != nil && strings.Contains(err.Error(), "reserved flags") { log.Printf("fixing header flags: %v", err); rebuildPacketWithFlags0x02() } Prevention
- Always OR 0x02 into SUBSCRIBE/UNSUBSCRIBE fixed header bytes
- Unit-test raw packet bytes against a reference capture
- Use TLS to rule out header corruption in transit
- Validate your encoder with an MQTT conformance/fuzz test suite
When it happens
Trigger: A client sends a SUBSCRIBE (expected fixed flags 0x2) or UNSUBSCRIBE (expected 0x2) whose low 4 header bits differ, e.g. 0x0, 0x3, or QoS bits erroneously set.
Common situations: Hand-rolled packet encoders forgetting the required 0010 bits, protocol fuzzers, corrupted header bytes on a non-TLS link, or a client library using an incompatible MQTT version framing.
Related errors
- 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
- with QoS=%v, packet identifier cannot be 0
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/e1035399a9527d9a.
Report an issue: GitHub.