{"record":{"id":"e1035399a9527d9a","repo":"nats-io/nats-server","slug":"wrong-ssubscribe-reserved-flags-x","errorCode":null,"errorMessage":"wrong %ssubscribe reserved flags: %x","messagePattern":"wrong (.+?)subscribe reserved flags: %x","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/mqtt.go","lineNumber":5301,"sourceCode":"//\n//////////////////////////////////////////////////////////////////////////////\n\nfunc (c *client) mqttParseSubs(r *mqttReader, b byte, pl int) (uint16, []*mqttFilter, error) {\n\treturn c.mqttParseSubsOrUnsubs(r, b, pl, true)\n}\n\nfunc (c *client) mqttParseSubsOrUnsubs(r *mqttReader, b byte, pl int, sub bool) (uint16, []*mqttFilter, error) {\n\tvar expectedFlag byte\n\tvar action string\n\tif sub {\n\t\texpectedFlag = mqttSubscribeFlags\n\t} else {\n\t\texpectedFlag = mqttUnsubscribeFlags\n\t\taction = \"un\"\n\t}\n\t// Spec [MQTT-3.8.1-1], [MQTT-3.10.1-1]\n\tif rf := b & 0xf; rf != expectedFlag {\n\t\treturn 0, nil, fmt.Errorf(\"wrong %ssubscribe reserved flags: %x\", action, rf)\n\t}\n\tpi, err := mqttParsePIPacket(r)\n\tif err != nil {\n\t\treturn 0, nil, err\n\t}\n\tend := r.pos + (pl - 2)\n\tvar filters []*mqttFilter\n\tfor r.pos < end {\n\t\t// Don't make a copy now because, this will happen during conversion\n\t\t// or when processing the sub.\n\t\ttopic, err := r.readBytes(\"topic filter\", false)\n\t\tif err != nil {\n\t\t\treturn 0, nil, err\n\t\t}\n\t\tif len(topic) == 0 {\n\t\t\treturn 0, nil, errMQTTTopicFilterCannotBeEmpty\n\t\t}\n\t\t// Spec [MQTT-3.8.3-1], [MQTT-3.10.3-1]","sourceCodeStart":5283,"sourceCodeEnd":5319,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/mqtt.go#L5283-L5319","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before (client-side header)\nheader := byte(subscribeType)<<4 // flags = 0000, wrong\n// after\nheader := byte(subscribeType)<<4 | 0x02 // reserved flags per spec","handlingStrategy":"validation","validationCode":"func subscribeHeader(packetType byte) byte { return packetType<<4 | 0x02 } // required reserved flags for SUB/UNSUB","typeGuard":"func hasValidSubscribeFlags(b byte) bool { return b&0x0f == 0x02 }","tryCatchPattern":"if err := subscribe(topic); err != nil && strings.Contains(err.Error(), \"reserved flags\") { log.Printf(\"fixing header flags: %v\", err); rebuildPacketWithFlags0x02() }","preventionTips":["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"],"tags":["mqtt","fixed-header","flags","subscribe","protocol-violation"],"backgroundTag":"mqtt-protocol-violation","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}