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

  1. 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.
  2. Enable MQTT trace logging to see the offending packet type and flags.
  3. Check any intermediate bridge/proxy that re-serializes MQTT frames.
  4. 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

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


AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02). Data as JSON: /api/errors/1ded6c8355d5261b. Report an issue: GitHub.