nats-io/nats-server · error
invalid fixed header flags %x for packet type %x
Error message
invalid fixed header flags %x for packet type %x
What it means
MQTT requires that each packet type carry specific values in the 4 fixed-header flag bits (DUP/QoS/RETAIN); most types mandate zero. mqttCheckFixedHeaderFlags computes the expected flags per packet type and raises this error when the received flags (lower nibble) don't match. Validated immediately after reading the first fixed-header byte.
Source
Thrown at server/mqtt.go:1012
}
return err
}
func mqttCheckFixedHeaderFlags(packetType, flags byte) error {
var expected byte
switch packetType {
case mqttPacketConnect, mqttPacketPubAck, mqttPacketPubRec, mqttPacketPubComp,
mqttPacketPing, mqttPacketDisconnect:
expected = 0
case mqttPacketPubRel, mqttPacketSub, mqttPacketUnsub:
expected = 0x2
case mqttPacketPub:
return nil
default:
return nil
}
if flags != expected {
return fmt.Errorf("invalid fixed header flags %x for packet type %x", flags, packetType)
}
return nil
}
func mqttCheckRemainingLength(packetType byte, pl int) error {
var expected int
switch packetType {
case mqttPacketConnect, mqttPacketPub, mqttPacketSub, mqttPacketUnsub:
return nil
case mqttPacketPubAck, mqttPacketPubRec, mqttPacketPubRel, mqttPacketPubComp:
expected = 2
case mqttPacketPing, mqttPacketDisconnect:
expected = 0
default:
return nil
}
if pl != expected {
return fmt.Errorf("invalid remaining length %d for packet type %x", pl, packetType)View on GitHub (pinned to 3a66a489d2)
Solutions
- Fix the client's fixed-header serialization: set the flag nibble to 0 for all packet types except PUBLISH (DUP/QoS/RETAIN) and validate QoS <= 2.
- Enable MQTT trace logging to see the offending packet type and flags.
- Check any intermediate bridge/proxy that re-serializes MQTT frames.
- Per MQTT spec, treat this as a protocol error and reconnect with a corrected encoder.
Example fix
// before: wrong flags on PUBREL writeByte(0x62); // flags=2 // after: PUBREL flags must be 0x2? no - must be 0b0010; correct per type writeByte(0x60 | 0x02); // PUBREL fixed header is 0x62 by spec; for types expecting 0 use 0x<type><<4>
Defensive patterns
Strategy: validation
Validate before calling
// Validate fixed-header flags per type before sending (MQTT 3.1.1 table)
const flagsFor = t => t === 3 ? undefined /* DUP/QoS/RETAIN */ : 0;
if (type !== 3 && (byte & 0x0F) !== 0) throw new Error('flags must be 0 for type ' + type); Type guard
function hasValidFlags(fixedHeaderByte, packetType) {
if (packetType === 3) return (fixedHeaderByte & 0x06) !== 0x06; // QoS must not be 3
return (fixedHeaderByte & 0x0F) === 0;
} Prevention
- Set flag nibble to 0 for every packet type except PUBLISH
- Never encode QoS 3 (0b11) on PUBLISH
- Unit-test your MQTT serializer against the spec's fixed-header table
- Avoid proxies that rewrite raw MQTT frames
When it happens
Trigger: A client sends e.g. a PUBREL/SUBSCRIBE/UNSUBSCRIBE/PINGREQ with nonzero flag bits, or a PUBLISH whose QoS bits are invalid (QoS 3). The check compares flags against mqttCheckFixedHeaderFlags's expected table and errors with fmt.Errorf("invalid fixed header flags %x for packet type %x", flags, packetType).
Common situations: Hand-rolled or buggy client serialization; bit-manipulation mistakes in custom bridges; corrupted frames from a faulty proxy; fuzz testing.
Related errors
- invalid remaining length %d for packet type %x
- topic filter cannot be empty
- malformed variable int
- the first packet should be a CONNECT (%v), got %v
- received unknown packet type %d
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/1ded6c8355d5261b.
Report an issue: GitHub.