crowdsecurity/crowdsec · error · InvalidIPOrRange
unable to convert '%s' to int: %w: %w
Error message
unable to convert '%s' to int: %w: %w
What it means
When the filter contains the 'ip' or 'range' key, ExpireDecisionsWithFilter parses the value into a csnet.Range via csnet.NewRange. On parse failure the error is wrapped with a misleading historical message ('unable to convert to int') plus the InvalidIPOrRange sentinel; it really means the value is not a valid IP address or CIDR range.
Source
Thrown at pkg/database/decisions.go:251
case "contains":
contains, err = strconv.ParseBool(value[0])
if err != nil {
return 0, nil, fmt.Errorf("invalid contains value: %w: %w", err, InvalidFilter)
}
case "scopes":
decisions = decisions.Where(decision.ScopeEQ(value[0]))
case "uuid":
decisions = decisions.Where(decision.UUIDIn(value...))
case "origin":
decisions = decisions.Where(decision.OriginEQ(value[0]))
case "value":
decisions = decisions.Where(decision.ValueEQ(value[0]))
case "type":
decisions = decisions.Where(decision.TypeEQ(value[0]))
case "ip", "range":
rng, err = csnet.NewRange(value[0])
if err != nil {
return 0, nil, fmt.Errorf("unable to convert '%s' to int: %w: %w", value[0], err, InvalidIPOrRange)
}
case "scenario":
decisions = decisions.Where(decision.ScenarioEQ(value[0]))
default:
return 0, nil, fmt.Errorf("'%s' doesn't exist: %w", param, InvalidFilter)
}
}
decisions, err = decisionIPFilter(decisions, contains, rng)
if err != nil {
return 0, nil, err
}
decisionsToDelete, err := decisions.All(ctx)
if err != nil {
c.Log.Warningf("ExpireDecisionsWithFilter : %s", err)
return 0, nil, fmt.Errorf("expire decisions with provided filter: %w", DeleteFail)
}View on GitHub (pinned to 909b515798)
Solutions
- Validate the value is a correct IP or CIDR (net.ParseIP / net.ParseCIDR) before passing it
- Correct the typo in the ip/range filter value (e.g. 192.168.1.0/24, not 192.168.1.300)
- Check errors.Is(err, database.InvalidIPOrRange) to distinguish this from other expiry failures
Example fix
// before
c.ExpireDecisionsWithFilter(ctx, map[string][]string{"range": {"10.0.0/24"}})
// after
if _, _, err := net.ParseCIDR("10.0.0.0/24"); err == nil {
c.ExpireDecisionsWithFilter(ctx, map[string][]string{"range": {"10.0.0.0/24"}})
} Defensive patterns
Strategy: validation
Validate before calling
func validIPOrRange(v string) bool {
if net.ParseIP(v) != nil { return true }
_, _, err := net.ParseCIDR(v)
return err == nil
} Try / catch
err := errors.Is(err, database.InvalidIPOrRange) // classify before showing to user
if errors.Is(err, database.InvalidIPOrRange) {
return status.Errorf(codes.InvalidArgument, "invalid ip/range filter: %v", err)
} Prevention
- Validate IP/CIDR with net.ParseIP/net.ParseCIDR before calling
- Reject hostnames — only literal IPs/CIDRs are accepted
- Strip prefixes like 'ip:' from pasted values
When it happens
Trigger: Calling ExpireDecisionsWithFilter with filter keys 'ip' or 'range' whose value is not a valid IP/CIDR (e.g. "192.168.1.300", "10.0.0/24", or a hostname).
Common situations: Hand-typed CLI arguments with typos in the CIDR; copy-pasted values retaining prefixes like 'ip:1.2.3.4'; scripts building ranges from unvalidated user input.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- unable to convert '%s' to int: %w
- invalid CIDR range '%s' for bot entry '%s' in %s: %w
- invalid ip range '%s': %w
- missing allowed_ranges value for api.server.auto_register
- out of bound gid
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/3d7cbcacf180f7b9.
Report an issue: GitHub.