crowdsecurity/crowdsec · error

invalid path regex '%s' for bot entry '%s' in %s: %w

Error message

invalid path regex '%s' for bot entry '%s' in %s: %w

What it means

botFileInit compiles each element of the entry's optional "paths" array as a case-insensitive regex. This error is thrown when any individual path pattern fails regexp.Compile. Like the UA regex, paths are validated eagerly so a broken entry never reaches match time.

Source

Thrown at pkg/exprhelpers/botfile.go:77

		return fmt.Errorf("missing mandatory 'name' field in %s: %s", filename, line)
	}

	if len(entry.IPs)+len(entry.Ranges)+len(entry.RDNS) == 0 {
		return fmt.Errorf("bot entry '%s' in %s has no identity verification (need at least one of ips/ranges/rdns)", entry.Name, filename)
	}

	var err error

	if entry.UserAgent != "" {
		if entry.uaRegex, err = compileBotRegex(entry.UserAgent); err != nil {
			return fmt.Errorf("invalid user_agent regex for bot entry '%s' in %s: %w", entry.Name, filename, err)
		}
	}

	for _, p := range entry.Paths {
		re, err := compileBotRegex(p)
		if err != nil {
			return fmt.Errorf("invalid path regex '%s' for bot entry '%s' in %s: %w", p, entry.Name, filename, err)
		}

		entry.pathRegexes = append(entry.pathRegexes, re)
	}

	entry.ipSet = make(map[netip.Addr]struct{}, len(entry.IPs))

	for _, ip := range entry.IPs {
		addr, err := netip.ParseAddr(ip)
		if err != nil {
			return fmt.Errorf("invalid IP '%s' for bot entry '%s' in %s: %w", ip, entry.Name, filename, err)
		}

		entry.ipSet[addr.Unmap()] = struct{}{}
	}

	for _, r := range entry.Ranges {
		prefix, err := netip.ParsePrefix(r)

View on GitHub (pinned to 909b515798)

Solutions

  1. Escape metacharacters in literal path text: "/search\?q=" instead of "/search?q=", "\.php" instead of ".php".
  2. Fix the syntax flaw the wrapped regexp/syntax error points to (unbalanced groups, dangling escapes, invalid repeat).
  3. Remove lookaheads/backreferences — Go's RE2 does not support them; restructure the pattern.
  4. Anchor patterns intentionally (^/admin) to avoid accidental broad matches once the regex compiles.
  5. Pre-compile each pattern with regexp.Compile in a scratch test before adding it to the data file.

Example fix

// before
{"name":"scanner","ips":["1.2.3.4"],"paths":["/wp-admin?section=("]}
// after
{"name":"scanner","ips":["1.2.3.4"],"paths":["^/wp-admin\\?.*"]}
Defensive patterns

Strategy: validation

Validate before calling

for _, p := range entry.Paths {
	if _, err := regexp.Compile("(?i)" + p); err != nil {
		// reject the entry before FileInit
	}
}
valid := err == nil

Try / catch

if err := exprhelpers.FileInit(botFile, "bots"); err != nil {
	if strings.Contains(err.Error(), "invalid path regex") {
		log.Errorf("offending path pattern: %v", err) // message echoes the pattern
	}
	return err
}

Prevention

When it happens

Trigger: A bots JSONL entry has a "paths" array where one element is an invalid Go RE2 regex, e.g. "paths":["/wp-login*"] (invalid repetition after literal — actually valid as .*) — more precisely patterns like "/admin(" or "\\". The message names the offending pattern, entry name, and file.

Common situations: Writing URL paths with unescaped regex metacharacters (? in query strings, . matching any char, + in URLs); typos in hand-written patterns; porting PCRE path filters with unsupported RE2 constructs.

Related errors


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