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

  1. Fix the encoder to compute remaining length as topic+payload sizes (plus 2 for pi when QoS>0) before writing the header
  2. Enable TLS on the client connection to rule out stream corruption in transit
  3. Verify the client library version for known framing bugs and upgrade
  4. 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

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


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