nats-io/nats-server · error
parse error: '%s'
Error message
parse error: '%s'
What it means
parseUnsubProto validates the argument count of an inbound UNSUB protocol line from a remote (route/leaf) connection: after the subject (and optional account/origin), only an optional queue name may follow. Any additional fields make the line unparseable and the server returns this generic 'parse error'.
Source
Thrown at server/route.go:1404
subjIdx int
)
// If `hasOrigin` is true, then it means this is a LS- with origin in proto.
if hasOrigin {
// We would not be here if there was not at least 1 field.
origin = args[0]
subjIdx = 1
}
// If there is an account in the protocol, bump the subject index.
if accInProto {
subjIdx++
}
switch len(args) {
case subjIdx + 1:
case subjIdx + 2:
queue = args[subjIdx+1]
default:
return nil, _EMPTY_, nil, nil, fmt.Errorf("parse error: '%s'", arg)
}
if accInProto {
// If there is an account in the protocol, it is before the subject.
accountName = string(args[subjIdx-1])
}
return origin, accountName, args[subjIdx], queue, nil
}
// Indicates no more interest in the given account/subject for the remote side.
func (c *client) processRemoteUnsub(arg []byte, leafUnsub bool) (err error) {
srv := c.srv
if srv == nil {
return nil
}
var accountName string
// Assume the account will be in the protocol.
accInProto := trueView on GitHub (pinned to 3a66a489d2)
Solutions
- Emit UNSUB as 'UNSUB <sid>[ <maxmsgs>]' with no extra fields on remote links
- Update the leaf/route peer client or bridge to a spec-compliant version
- Enable trace logging to capture the offending UNSUB line
- Verify account/origin sentinel placement matches the negotiated protocol features
Example fix
// before (bridge) "UNSUB sid 1 extra\r\n" // after "UNSUB sid 1\r\n"
Defensive patterns
Strategy: validation
Validate before calling
// Validate UNSUB line shape before forwarding on a remote link
parts := strings.Fields(line)
if len(parts) > 3 { // UNSUB sid [maxmsgs] plus optional queue per remote protocol
return fmt.Errorf("too many fields in remote UNSUB: %v", parts)
} Prevention
- Emit UNSUB with only sid and optional max-msgs
- Keep leaf/route peers updated to spec-compliant versions
- Trace-verify forwarded UNSUB lines in integration tests
When it happens
Trigger: UNSUB line with too many fields, e.g. 'UNSUB <sid> <maxmsgs> <extra>' when forwarded remotely, or a subject+queue plus unexpected extra tokens.
Common situations: Leaf/route connections from third-party or older implementations that append extra fields to UNSUB, protocol translation bugs in bridges, or corrupted frames.
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
- processRemoteUnsub %s
- invalid publish message, variable header exceeds remaining l
- restore for stream '%s > %s' requires reply subject for each
- restore for stream '%s > %s' received short chunk
- processRoutedHeaderMsgArgs Header Size larger then TotalSize
AI-assisted analysis of nats-io/nats-server@3a66a489d2 (2026-09-02).
Data as JSON: /api/errors/768f563ab65dc81a.
Report an issue: GitHub.