crowdsecurity/crowdsec · error
bot entry '%s' in %s has no identity verification (need at l
Error message
bot entry '%s' in %s has no identity verification (need at least one of ips/ranges/rdns)
What it means
botFileInit enforces that every bot entry carries at least one identity-verification mechanism: ips, ranges, or rdns. This error is thrown when an entry has none of these, i.e. it would only (potentially) match on user_agent/paths. UA-only entries are rejected by design because a User-Agent is trivially spoofable — identity must be corroborated by IP, CIDR, or forward-confirmed reverse DNS.
Source
Thrown at pkg/exprhelpers/botfile.go:63
return regexp.Compile("(?i)" + pattern) // Force case insensitive match
}
func botFileInit(filename string, line string) error {
entry := &botEntry{}
dec := json.NewDecoder(strings.NewReader(line))
dec.DisallowUnknownFields()
if err := dec.Decode(entry); err != nil {
return fmt.Errorf("failed to parse JSON line in %s: %w", filename, err)
}
if entry.Name == "" {
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)
}View on GitHub (pinned to 909b515798)
Solutions
- Add at least one identity source to the entry: verified ips (e.g. Google/BD published ranges), a "ranges" CIDR list, or an "rdns" pattern.
- For crawler bots, fetch the operator's official published IP ranges (e.g. https://developers.google.com/search/apis/ipranges) and put them in "ranges".
- Use "rdns":["(^|\.)googlebot\.com$"] style forward-confirmed reverse-DNS patterns when IPs are not published.
- If you truly want UA-only matching, this loader is not the place — use a parse/expression rule in a scenario instead.
Example fix
// before
{"name":"googlebot","user_agent":"Googlebot"}
// after
{"name":"googlebot","user_agent":"Googlebot","rdns":["(^|\.)googlebot\.com$"]} Defensive patterns
Strategy: validation
Validate before calling
var probe struct {
IPs []string `json:"ips"`
Ranges []string `json:"ranges"`
RDNS []string `json:"rdns"`
}
_ = json.Unmarshal([]byte(line), &probe)
valid := len(probe.IPs)+len(probe.Ranges)+len(probe.RDNS) > 0 Try / catch
if err := exprhelpers.FileInit(botFile, "bots"); err != nil {
if strings.Contains(err.Error(), "no identity verification") {
log.Errorf("entry needs ips/ranges/rdns: %v", err)
}
return err
} Prevention
- Never author UA-only entries; always attach published IP ranges or an rdns pattern.
- For big operators, pull official IP-range feeds (e.g. Google ipranges JSON) into "ranges".
- Remember empty arrays count as zero — remove unused empty arrays rather than relying on them.
- Prefer rdns for operators without stable published ranges; anchor the regex.
When it happens
Trigger: A bots JSONL line defines only name (+ optionally user_agent/paths) with no "ips", "ranges", or "rdns" arrays, e.g. {"name":"googlebot","user_agent":"Googlebot"}.
Common situations: Porting a UA-only blocklist from another tool where UA matching alone was accepted; authoring a new bot entry and assuming UA is sufficient; copying an example that showed only the UA field; empty arrays like "ips":[] also trigger since len sums to 0.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- failed to parse JSON line in %s: %w
- missing mandatory 'name' field in %s: %s
- 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/064538e0f2405356.
Report an issue: GitHub.