nats-io/nats-server · error
invalid remaining length %d for PUBLISH packet
Error message
invalid remaining length %d for PUBLISH packet
What it means
The computed PUBLISH payload size (remaining length pl minus the variable header bytes consumed) came out negative, meaning the declared remaining length is smaller than the variable header itself. The server rejects the packet as malformed because the frame is internally inconsistent.
Source
Thrown at server/mqtt.go:4312
}
if qos > 0 {
pp.pi, err = r.readUint16("packet identifier")
if err != nil {
return err
}
if pp.pi == 0 {
return fmt.Errorf("with QoS=%v, packet identifier cannot be 0", qos)
}
} else {
pp.pi = 0
}
// The message payload will be the total packet length minus
// what we have consumed for the variable header
payloadSize := pl - (r.pos - start)
if payloadSize < 0 {
return fmt.Errorf("invalid remaining length %d for PUBLISH packet", pl)
}
pp.sz = payloadSize
if pp.sz > 0 {
start = r.pos
r.pos += pp.sz
pp.msg = r.buf[start:r.pos]
} else if pp.sz == 0 {
pp.msg = nil
} else {
return errMQTTInvalidPublishLength
}
return nil
}
func mqttValidateTopic(topic []byte, field string) error {
if !utf8.Valid(topic) {
return fmt.Errorf("invalid utf8 for %s %q", field, topic)
}View on GitHub (pinned to 3a66a489d2)
Solutions
- Fix the encoder to compute remaining length as topic+payload sizes (plus 2 for pi when QoS>0) before writing the header
- Enable TLS on the client connection to rule out stream corruption in transit
- Verify the client library version for known framing bugs and upgrade
- Use a MQTT protocol analyzer (e.g. Wireshark MQTT dissector) on the client connection to inspect the malformed frame
Example fix
// before
pl := len(topic) + len(payload)
// after
pl := 2 + len(topic) + len(payload)
if qos > 0 { pl += 2 } Defensive patterns
Strategy: validation
Validate before calling
func publishRemainingLen(topic []byte, payload []byte, qos byte) int {
n := 2 + len(topic) + len(payload)
if qos > 0 { n += 2 }
return n
} Type guard
func hasPlausibleFrame(pl int, headerLen int) bool { return pl >= headerLen } Try / catch
if _, err := conn.Write(pkt); err != nil || brokerClosed { log.Printf("malformed PUBLISH rejected: %v", err); reencodeAndResend() } Prevention
- Compute remaining length after the variable header is fully assembled
- Unit-test PUBLISH encoding with empty topics and empty payloads
- Use TLS to detect/circumvent stream corruption
- Validate frames with a MQTT dissector during development
When it happens
Trigger: A PUBLISH packet whose remaining-length field is less than the combined size of topic length, topic, and (for QoS>0) packet identifier bytes.
Common situations: Truncated or corrupted TCP streams without TLS/checksum protection, hand-written packet encoders computing remaining length incorrectly, fuzz testing, or a buggy client library miscounting header bytes.
Related errors
- topic filter cannot be empty
- malformed variable int
- invalid fixed header flags %x for packet type %x
- invalid remaining length %d for packet type %x
- MQTT clients over websocket must connect to the Websocket po
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/c9b96c992305ecca.
Report an issue: GitHub.