crowdsecurity/crowdsec · error

pid inside tag must be a number

Error message

pid inside tag must be a number

What it means

After reading the alphanumeric TAG, parseTag optionally parses a PID bracketed as 'tag[123]'. Every byte between '[' and ']' must be a digit; if a non-digit appears, it returns 'pid inside tag must be a number'. It is thrown because rfc3164 PIDs are numeric and the parser stores them in RFC3164.PID as a numeric string.

Source

Thrown at pkg/acquisition/modules/syslog/internal/parser/rfc3164/parse.go:169

	r.Tag = string(tag)

	if r.position == r.len {
		return nil
	}

	c := r.buf[r.position]
	if c == '[' {
		hasPid = true
		r.position++
		for r.position < r.len {
			c = r.buf[r.position]
			if c == ']' {
				pidEnd = true
				r.position++
				break
			}
			if c < '0' || c > '9' {
				return errors.New("pid inside tag must be a number")
			}
			tmpPid = append(tmpPid, c)
			r.position++
		}
	}

	if hasPid && !pidEnd {
		return errors.New("pid inside tag must be closed with ']'")
	}

	if hasPid {
		r.PID = string(tmpPid)
	}
	return nil
}

func (r *RFC3164) parseMessage() error {
	err := r.parseTag()

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect the raw message around the '[' following the tag; ensure the enclosed value is the numeric PID (e.g. 'sshd[1234]:') or that '[' is not a PID at all.
  2. Fix the emitting application/template so the bracketed suffix contains only digits, or remove the bracket suffix entirely.
  3. If '[' belongs to the message body, insert a ':' right after the tag (e.g. 'tag: [something] msg') so the bracketed text is treated as message content... note the parser treats '[' immediately after the tag as a PID regardless, so best to change the message format at the source.
  4. Preprocess/rewrite such lines upstream (regex normalization) before syslog acquisition so bracketed non-numeric tokens are escaped or separated.
  5. If the source cannot be fixed, route these messages to the RFC5424 parser or a custom parsing path that tolerates non-numeric bracket content.

Example fix

// before: non-numeric bracket content
r.Parse([]byte("<34>Feb  3 09:12:01 host md[raid]: resync")) // pid inside tag must be a number

// after: numeric pid, or colon before message
r.Parse([]byte("<34>Feb  3 09:12:01 host md: [raid] resync"))
Defensive patterns

Strategy: validation

Validate before calling

func pidBracketIsNumeric(msg string) bool {
	// find tag token then check any immediately-following [ ... ] holds digits only
	parts := strings.SplitN(msg, " ", 4)
	if len(parts) < 4 { return true }
	tag := parts[3]
	i := strings.IndexByte(tag, '[')
	if i < 0 { return true }
	j := strings.IndexByte(tag[i+1:], ']')
	if j < 0 { return false }
	pid := tag[i+1 : i+1+j]
	for _, c := range []byte(pid) {
		if c < '0' || c > '9' { return false }
	}
	return true
}

Try / catch

if err := parser.Parse(line); err != nil {
	if strings.Contains(err.Error(), "pid inside tag must be a number") {
		line = escapeBracketsAfterTag(line) // rewrite, e.g. move '[' content after ':'
	}
}

Prevention

When it happens

Trigger: Calling Parse on a message whose tag contains a bracketed value with non-digit characters, e.g. 'kernel[abc]:' or 'app[x1]:'; also a tag like 'systemd[1a]' mid-stream. Also cases where '[' is part of the message body and gets attached because the preceding tag is alphanumeric (e.g. 'md[raid error]' style text).

Common situations: Applications emitting bracketed non-numeric suffixes (thread names, raid arrays, instance names) that look like PIDs; a message body starting with word[...] where the bracket content is not a PID; templating bugs that place '%proc%' or a hostname inside the brackets.

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/92de6c4e6b89d9be. Report an issue: GitHub.