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
- 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).
- Use an official NATS client library instead of hand-crafting protocol frames.
- 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.
- 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
- Use an official NATS client library; do not hand-write HPUB frames.
- Verify header/total sizes count bytes of header-block+payload exactly.
- Always terminate protocol lines with CRLF.
- Test header publishing against a local server before production.
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
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- bad message header detected
- processHeaderPub Bad or Missing Header Size: %q
- processPub Parse Error: %q
- account jwt not found
- auth callout violation: auth callout response is not for exp
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/64b141e29886115c.
Report an issue: GitHub.