nats-io/nats-server · error
bad message header detected
Error message
bad message header detected
What it means
ErrBadMsgHeader is returned by the protocol parser when a message's header block is malformed—e.g., an invalid header line, missing HMSG/PUB-terminating structure, or a headers length that does not match the payload framing. Declared at server/errors.go:181, it signals the server (or embedded client) detected corrupt or non-conforming header data while parsing an inbound message.
Source
Thrown at server/errors.go:181
// ErrGatewayNameHasSpaces signals that the gateway name contains spaces, which is not allowed.
ErrGatewayNameHasSpaces = errors.New("gateway name cannot contain spaces")
// ErrNoSysAccount is returned when an attempt to publish or subscribe is made
// when there is no internal system account defined.
ErrNoSysAccount = errors.New("system account not setup")
// ErrRevocation is returned when a credential has been revoked.
ErrRevocation = errors.New("credentials have been revoked")
// ErrServerNotRunning is used to signal an error that a server is not running.
ErrServerNotRunning = errors.New("server is not running")
// ErrServerNameHasSpaces signals that the server name contains spaces, which is not allowed.
ErrServerNameHasSpaces = errors.New("server name cannot contain spaces")
// ErrBadMsgHeader signals the parser detected a bad message header
ErrBadMsgHeader = errors.New("bad message header detected")
// ErrMsgHeadersNotSupported signals the parser detected a message header
// but they are not supported on this server.
ErrMsgHeadersNotSupported = errors.New("message headers not supported")
// ErrNoRespondersRequiresHeaders signals that a client needs to have headers
// on if they want no responders behavior.
ErrNoRespondersRequiresHeaders = errors.New("no responders requires headers support")
// ErrClusterNameConfigConflict signals that the options for cluster name in cluster and gateway are in conflict.
ErrClusterNameConfigConflict = errors.New("cluster name conflicts between cluster and gateway definitions")
// ErrClusterNameRemoteConflict signals that a remote server has a different cluster name.
ErrClusterNameRemoteConflict = errors.New("cluster name from remote server conflicts")
// ErrClusterNameHasSpaces signals that the cluster name contains spaces, which is not allowed.
ErrClusterNameHasSpaces = errors.New("cluster name cannot contain spaces")
View on GitHub (pinned to 3a66a489d2)
Solutions
- Fix the producing client to emit valid HMSG framing: correct header length + total length and CRLF-delimited `Key: Value` lines ending with a blank line.
- Use an official NATS client's header API (nats.MsgHeader) instead of building header strings manually.
- Check for proxies/middleboxes that alter message bytes and bypass them.
- Upgrade old clients/servers so header support (2.2+) is consistent across the deployment.
Example fix
// before: manual header bytes without CRLF
payload := []byte("key:value")
// after
msg := nats.NewMsg("subj")
msg.Header.Set("key", "value")
msg.Data = body
nc.PublishMsg(msg) Defensive patterns
Strategy: try-catch
Validate before calling
// For custom producers, validate header bytes before publishing: // - every line matches ^[!-9;-~]+: .*$ (printable, colon present) // - lines terminated with CRLF and a final blank CRLF line // - declared header length equals actual header byte count
Try / catch
err := nc.PublishMsg(msg)
if err != nil && strings.Contains(err.Error(), "bad message header detected") {
// fall back to republishing without headers and log the malformed header
} Prevention
- Use official client header APIs (nats.MsgHeader) instead of hand-built header bytes.
- Never run byte-rewriting proxies between clients and servers.
- Pin client/server versions >= 2.2 where header support is stable.
- Add raw-protocol fuzz/round-trip tests if you speak the wire protocol directly.
When it happens
Trigger: A client publishes HMSG frames with malformed header text (missing CRLF, invalid key/value encoding); a proxy or custom client corrupts the header length fields; version mismatch where an old server receives header messages it mis-parses; fuzzing or buggy SDK writing raw protocol.
Common situations: Hand-rolled NATS clients or middleboxes rewriting messages; tests using raw TCP sockets with malformed HMSG payloads; upgraded clients sending headers to infrastructure that mangles them.
Related errors
- processHeaderPub Parse Error: %q
- processHeaderPub Bad or Missing Header Size: %q
- processPub Parse Error: %q
- %s parser ERROR, state=%d, i=%d: proto='%s...'
- account jwt not found
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/f99a6bea67e1d38e.
Report an issue: GitHub.