crowdsecurity/crowdsec · warning · InvalidIPOrRange
unable to convert '%s' to int: %w: %w
Error message
unable to convert '%s' to int: %w: %w
What it means
applyDecisionFilter fails when the 'ip' or 'range' query parameter cannot be parsed into a network range by csnet.NewRange. The message's 'to int' wording is legacy/misleading; the real issue is an invalid IP address or CIDR value, wrapped with sentinel InvalidIPOrRange.
Source
Thrown at pkg/database/decisionfilter.go:80
query = query.Where(decision.TypeEQ(value[0]))
case "origins":
query = query.Where(
decision.OriginIn(strings.Split(value[0], ",")...),
)
case "scenarios_containing":
predicates := decisionPredicatesFromStr(value[0], decision.ScenarioContainsFold)
query = query.Where(decision.Or(predicates...))
case "scenarios_not_containing":
predicates := decisionPredicatesFromStr(value[0], decision.ScenarioContainsFold)
query = query.Where(decision.Not(
decision.Or(
predicates...,
),
))
case "ip", "range":
rng, err = csnet.NewRange(value[0])
if err != nil {
return nil, fmt.Errorf("unable to convert '%s' to int: %w: %w", value[0], err, InvalidIPOrRange)
}
case "limit":
limit, err := strconv.Atoi(value[0])
if err != nil {
return nil, fmt.Errorf("invalid limit value: %w: %w", err, InvalidFilter)
}
query = query.Limit(limit)
case "offset":
offset, err := strconv.Atoi(value[0])
if err != nil {
return nil, fmt.Errorf("invalid offset value: %w: %w", err, InvalidFilter)
}
query = query.Offset(offset)
case "id_gt":
id, err := strconv.Atoi(value[0])
if err != nil {View on GitHub (pinned to 909b515798)
Solutions
- Validate the value is a valid IP or CIDR (net.ParseIP / net.ParseCIDR) before sending.
- Use full CIDR form for ranges: 10.0.0.0/24, not 10.0.0/24.
- Remove the ip/range parameter to query without an IP filter.
- For IPv6, ensure correct compressed notation (e.g. 2001:db8::/32).
Example fix
// before GET /v1/decisions?range=192.168.1.0/33 // after GET /v1/decisions?range=192.168.1.0/24
Defensive patterns
Strategy: validation
Validate before calling
func validIPOrRange(v string) bool {
if v == "" { return false }
if strings.Contains(v, "/") {
_, _, err := net.ParseCIDR(v)
return err == nil
}
return net.ParseIP(v) != nil
} Try / catch
if !validIPOrRange(ipParam) {
return fmt.Errorf("refusing LAPI call: %q is not an IP or CIDR", ipParam)
}
resp, err := lapi.GetDecisions(ctx, models.GetDecisionsOpts{IP: &ipParam})
if err != nil && strings.Contains(err.Error(), "InvalidIPOrRange") {
return fmt.Errorf("bad ip/range %q: %w", ipParam, err)
} Prevention
- Validate IPs/CIDRs with net.ParseIP/net.ParseCIDR before sending
- Use full CIDR notation for ranges
- Never pass hostnames where an IP is expected
- Handle empty strings explicitly instead of interpolating them
When it happens
Trigger: Calling LAPI decision endpoints with ?ip=not-an-ip, ?range=10.0.0/24 (bad CIDR), ?ip=999.1.1.1, or an IPv6 with wrong syntax.
Common situations: Hand-built curl commands with typos in CIDR notation; scripts interpolating empty strings for ip/range; mixing prefix lengths wrong (e.g. /33); passing a hostname instead of an IP.
Understand the failure class
Background: "Invalid query parameter" / "Failed to parse value of ...": fixing bad query string parameters across APIs — this error's family across 36 libraries.
Related errors
- invalid contains value: %w: %w
- invalid limit value: %w: %w
- invalid offset value: %w: %w
- invalid id_gt value: %w: %w
- invalid port %d
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/16ed73e1f2f8d27c.
Report an issue: GitHub.