nats-io/nats-server · error

processHeaderPub Parse Error: %q

Error message

processHeaderPub Parse Error: %q

What it means

The server failed to parse a HPUB protocol message: after the opcode, exactly four arguments (subject, reply, header-size, body-size) are expected, and the received argument count did not match, so the header-publish line is malformed. The server returns this error and will close the connection, since the protocol stream is now ambiguous.

Source

Thrown at server/client.go:2919

	c.pa.arg = arg
	switch len(args) {
	case 3:
		c.pa.subject = args[0]
		c.pa.reply = nil
		c.pa.hdr = parseSize(args[1])
		c.pa.size = parseSize(args[2])
		c.pa.hdb = args[1]
		c.pa.szb = args[2]
	case 4:
		c.pa.subject = args[0]
		c.pa.reply = args[1]
		c.pa.hdr = parseSize(args[2])
		c.pa.size = parseSize(args[3])
		c.pa.hdb = args[2]
		c.pa.szb = args[3]
	default:
		return fmt.Errorf("processHeaderPub Parse Error: %q", arg)
	}
	if c.pa.hdr < 0 {
		return fmt.Errorf("processHeaderPub Bad or Missing Header Size: %q", arg)
	}
	// If number overruns an int64, parseSize() will have returned a negative value
	if c.pa.size < 0 {
		return fmt.Errorf("processHeaderPub Bad or Missing Total Size: %q", arg)
	}
	if c.pa.hdr > c.pa.size {
		return fmt.Errorf("processHeaderPub Header Size larger then TotalSize: %q", arg)
	}
	maxPayload := atomic.LoadInt32(&c.mpay)
	// Use int64() to avoid int32 overrun...
	if maxPayload != jwt.NoLimit && int64(c.pa.size) > int64(maxPayload) {
		// If we are given the remaining read buffer (since we do blind reads
		// we may have the beginning of the message header/payload), we will
		// look for the tracing header and if found, we will generate a
		// trace event with the max payload ingress error.

View on GitHub (pinned to 3a66a489d2)

Solutions

  1. Send the correct HPUB form: with reply 'HPUB <subject> <reply> <hdr_size> <total_size>'; without reply 'HPUB <subject> <hdr_size> <total_size>' (still 4 tokens after opcode handling — verify against the protocol spec your server version implements).
  2. Use an official NATS client library instead of hand-crafting protocol frames.
  3. Check that sizes are decimal integers and the CRLF-terminated line carries exactly the expected fields, with the payload of exactly hdr+size bytes following.
  4. Capture the raw bytes on the wire (tcpdump/Wireshark) to see the actual malformed line and correct the producer.

Example fix

// before
conn.Write([]byte("HPUB foo 10\r\nNATS/1.0\r\nX: 1\r\n\r\nbody")) // missing size arg
// after
conn.Write([]byte("HPUB foo 10 14\r\nNATS/1.0\r\nX: 1\r\n\r\nbody"))
Defensive patterns

Strategy: try-catch

Validate before calling

func validateHPUB(subject, reply string, hdr, size int) error {
    if subject == "" || hdr < 0 || size < 0 { return fmt.Errorf("bad HPUB args") }
    return nil
}

Try / catch

if err := conn.Flush(); err != nil {
    if strings.Contains(err.Error(), "processHeaderPub Parse Error") {
        // malformed HPUB: reconnect with a compliant client library
        log.Printf("HPUB frame malformed, rebuilding protocol writer: %v", err)
    }
}

Prevention

When it happens

Trigger: Sending a 'HPUB' line to the server whose token count != 4 (e.g. missing header/size fields, an empty reply token with a stray space creating wrong arg count, or trailing/extra tokens); typically from a hand-rolled or buggy client implementation.

Common situations: Custom NATS clients implementing headers incorrectly (HPUB <subject> <reply> <hdr> <size> vs the no-reply form HPUB <subject> <hdr> <size> mishandled); newline/CRLF handling bugs that merge two protocol lines; fuzzing or test tooling sending truncated HPUB lines.

Understand the failure class

Related errors


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