crowdsecurity/crowdsec · error

PRI must be a number

Error message

PRI must be a number

What it means

parsePRI reads the syslog PRI field between '<' and '>'. Each character inside the brackets must be a decimal digit; if any character before the closing '>' is not '0'-'9', the parser rejects the line because PRI is defined by RFC 5424 as a numeric priority value. This indicates the line is not a well-formed RFC 5424 syslog message.

Source

Thrown at pkg/acquisition/modules/syslog/internal/parser/rfc5424/parse.go:59

}

func (r *RFC5424) parsePRI() error {
	pri := 0

	if r.buf[r.position] != '<' {
		return errors.New("PRI must start with '<'")
	}

	r.position++

	for r.position < r.len {
		c := r.buf[r.position]
		if c == '>' {
			r.position++
			break
		}
		if c < '0' || c > '9' {
			return errors.New("PRI must be a number")
		}
		pri = pri*10 + int(c-'0')
		r.position++
	}

	if pri > 999 {
		return errors.New("PRI must be up to 3 characters long")
	}

	if r.position == r.len && r.buf[r.position-1] != '>' {
		return errors.New("PRI must end with '>'")
	}

	r.PRI = pri
	return nil
}

func (r *RFC5424) parseVersion() error {

View on GitHub (pinned to 909b515798)

Solutions

  1. Verify the sender actually emits RFC 5424 format: the message must begin "<PRI>VERSION ..."; use a different parser/decoder for RFC 3164 lines.
  2. Inspect the raw line (log the buffer before Parse) to find what non-numeric character follows the '<'.
  3. Check network path (UDP vs TCP framing) for truncation or interleaved data corrupting the message start.

Example fix

// before
parser.Parse([]byte("<34 Notice>1 2024-01-01T00:00:00Z host app 1 - msg"))
// after (PRI must be purely numeric)
parser.Parse([]byte("<34>1 2024-01-01T00:00:00Z host app 1 - msg"))
Defensive patterns

Strategy: validation

Validate before calling

// Go: check the PRI is '<' followed by digits and '>' before parsing
func looksLikePRI(line []byte) bool {
	if len(line) < 3 || line[0] != '<' {
		return false
	}
	i := 1
	for i < len(line) && line[i] != '>' {
		if line[i] < '0' || line[i] > '9' {
			return false
		}
		i++
	}
	return i < len(line) && line[i] == '>' && i <= 4
}

Try / catch

if err := parser.Parse(line); err != nil {
	if strings.Contains(err.Error(), "PRI must be a number") {
		// route to legacy/rfc3164 parser or drop to deadletter
	}
}

Prevention

When it happens

Trigger: Calling RFC5424.Parse on a line like "<12ab>1 ..." or "<PR>1 ..." where a non-digit character appears between '<' and '>'. Also fired when PRI exceeds 3 digits and the 4th character is not '>' (e.g. "<12345..." hits '4', a digit, then later overflow check applies; but "<12x4>" hits 'x' immediately).

Common situations: A syslog sender emitting RFC 3164 (legacy) lines, non-syslog garbage on the socket, a relay mangling the header, or UDP datagram fragmentation/interleaving corrupting the message start.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/6da000853a796515. Report an issue: GitHub.