nats-io/nats-server · error
received unknown packet type %d
Error message
received unknown packet type %d
What it means
After CONNECT, the MQTT read loop dispatches packets by their 4-bit type in the fixed header's high nibble (pt>>4). If the type does not match any known MQTT control packet handled by the switch, this error is produced and the connection is dropped. It signals a corrupt or malicious/non-conformant client stream.
Source
Thrown at server/mqtt.go:989
}
case mqttPacketDisconnect:
if trace {
c.traceInOp("DISCONNECT", nil)
}
// Normal disconnect, we need to discard the will.
// Spec [MQTT-3.1.2-8]
c.mu.Lock()
if c.mqtt.cp != nil {
c.mqtt.cp.will = nil
}
c.mu.Unlock()
s.mqttHandleClosedClient(c)
c.closeConnection(ClientClosed)
return nil
default:
err = fmt.Errorf("received unknown packet type %d", pt>>4)
}
}
if err == nil && rd > 0 {
r.reader.SetReadDeadline(time.Now().Add(rd))
}
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 nilView on GitHub (pinned to 3a66a489d2)
Solutions
- Fix or upgrade the client library so it never emits reserved/unknown packet types.
- Inspect the packet trace (enable debug/trace logging) to capture the offending bytes and identify the sender.
- Check network path for proxies/terminators that could corrupt framing.
- Treat the disconnect as expected server behavior: per MQTT spec, malformed packets justify closing the connection.
Defensive patterns
Strategy: validation
Validate before calling
// Client-side sanity: assert every emitted packet type is a legal MQTT type
const VALID = new Set([1,2,3,4,6,7,8,10,11,12,13,14]);
if (!VALID.has(pt >> 4)) throw new Error(`invalid packet type ${pt >> 4}`); Type guard
function isKnownMqttPacketType(pt) { const t = pt >> 4; return t >= 1 && t <= 14 && t !== 5 && t !== 9; } Prevention
- Use a maintained MQTT client library rather than hand-rolled framing
- Never send reserved packet types (0, 5, 9) or type > 14
- Check TLS/proxy paths for corruption
- Enable server MQTT trace to capture offending bytes
When it happens
Trigger: A client sends a packet whose fixed-header type bits (pt>>4) fall outside the handled set (CONNECT, PUBLISH, PUBACK, PUBREC, PUBREL, PUBCOMP, SUBSCRIBE, UNSUBSCRIBE, PINGREQ, DISCONNECT). Seen in the default branch of the read-loop switch.
Common situations: Data corruption on the wire; a custom/broken MQTT client implementation; a proxy mangling bytes; protocol-level confusion where reserved packet types (e.g. type 0) are sent; fuzz tests feeding random bytes.
Related errors
- the first packet should be a CONNECT (%v), got %v
- 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
- invalid null character in %s %q
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/d081b25cf31a919c.
Report an issue: GitHub.