crowdsecurity/crowdsec · error

empty rdns pattern for bot entry '%s' in %s

Error message

empty rdns pattern for bot entry '%s' in %s

What it means

Entries in the "rdns" array are regexes matched against forward-confirmed reverse-DNS names. botFileInit explicitly rejects an empty string pattern because an empty regex matches every PTR-confirmed host — almost certainly a configuration mistake that would mark all rDNS-resolvable clients as the bot. This guard fails the load instead.

Source

Thrown at pkg/exprhelpers/botfile.go:107

		}

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

	for _, r := range entry.Ranges {
		prefix, err := netip.ParsePrefix(r)
		if err != nil {
			return fmt.Errorf("invalid CIDR range '%s' for bot entry '%s' in %s: %w", r, entry.Name, filename, err)
		}

		entry.prefixes = append(entry.prefixes, prefix.Masked())
	}

	for _, p := range entry.RDNS {
		// an empty pattern matches every PTR-confirmed host: almost
		// certainly a mistake, reject it
		if p == "" {
			return fmt.Errorf("empty rdns pattern for bot entry '%s' in %s", entry.Name, filename)
		}

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

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

	dataFileBots[filename] = append(dataFileBots[filename], entry)

	return nil
}

// parseBotAddr normalizes a source address as found in HTTP contexts:
// bare IP, "ip:port", "[v6]:port". The zone is stripped and IPv4-mapped
// IPv6 is unmapped so comparisons against load-time-parsed IPs/ranges are

View on GitHub (pinned to 909b515798)

Solutions

  1. Replace the empty string with an anchored regex for the operator's domain, e.g. "(^|\.)googlebot\.com$".
  2. Delete the empty element from the rdns array if it is stray.
  3. If rDNS matching is not needed, remove the rdns field entirely and rely on ips/ranges (at least one identity source must remain, or error 1042 fires).
  4. Check your generator script for an unset variable producing "" in the output.

Example fix

// before
{"name":"bingbot","rdns":[""]}
// after
{"name":"bingbot","rdns":["(^|\.)bing\.com$"]}
Defensive patterns

Strategy: validation

Validate before calling

for _, p := range entry.RDNS {
	if strings.TrimSpace(p) == "" {
		// reject before FileInit: empty rdns pattern matches every PTR-confirmed host
	}
}
valid := !hasEmpty

Try / catch

if err := exprhelpers.FileInit(botFile, "bots"); err != nil {
	if strings.Contains(err.Error(), "empty rdns pattern") {
		log.Errorf("fill in the rdns pattern: %v", err)
	}
	return err
}

Prevention

When it happens

Trigger: A bots JSONL entry has "rdns":[""] or "rdns":["", "(^|\.)example\.com$"] — any empty string element triggers the error for that entry.

Common situations: A templating/generation script left an empty pattern where a domain should have been substituted; hand-editing removed the pattern but kept the empty quotes; copying a list where a blank line became an empty array element.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


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