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 areView on GitHub (pinned to 909b515798)
Solutions
- Replace the empty string with an anchored regex for the operator's domain, e.g. "(^|\.)googlebot\.com$".
- Delete the empty element from the rdns array if it is stray.
- 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).
- 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
- Never emit empty strings into rdns arrays from generator scripts; skip empty values instead.
- Always give each rdns element an anchored domain regex.
- If a template variable can be empty, validate it before rendering the entry.
- Remove the rdns field entirely when rDNS matching is not intended.
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
- missing mandatory 'name' field in %s: %s
- bot entry '%s' in %s has no identity verification (need at l
- invalid user_agent regex for bot entry '%s' in %s: %w
- invalid path regex '%s' for bot entry '%s' in %s: %w
- invalid IP '%s' for bot entry '%s' in %s: %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/4b761fe12e45da9b.
Report an issue: GitHub.