crowdsecurity/crowdsec · error
transforming last address of range: %w
Error message
transforming last address of range: %w
What it means
After converting the first address of a net.IPNet, Range2Ints computes the last address via LastAddress and converts it too. If IP2Ints fails on the last address, the error is wrapped with this message. LastAddress ORs the hostmask into the base IP, so failure here means the resulting broadcast address is nil or has an invalid byte length.
Source
Thrown at pkg/types/ip.go:71
if err != nil {
return -1, 0, 0, 0, 0, fmt.Errorf("invalid ip address '%s': %w", anyIP, err)
}
return sz, start, end, start, end, nil
}
/*size (16|4), nw_start, suffix_start, nw_end, suffix_end, error*/
func Range2Ints(network net.IPNet) (int, int64, int64, int64, int64, error) {
szStart, nwStart, sfxStart, err := IP2Ints(network.IP)
if err != nil {
return -1, 0, 0, 0, 0, fmt.Errorf("converting first ip in range: %w", err)
}
lastAddr := LastAddress(network)
szEnd, nwEnd, sfxEnd, err := IP2Ints(lastAddr)
if err != nil {
return -1, 0, 0, 0, 0, fmt.Errorf("transforming last address of range: %w", err)
}
if szEnd != szStart {
return -1, 0, 0, 0, 0, fmt.Errorf("inconsistent size for range first(%d) and last(%d) ip", szStart, szEnd)
}
return szStart, nwStart, sfxStart, nwEnd, sfxEnd, nil
}
func uint2int(u uint64) int64 {
var ret int64
if u == math.MaxInt64 {
ret = 0
} else if u == math.MaxUint64 {
ret = math.MaxInt64
} else if u > math.MaxInt64 {
u -= math.MaxInt64
ret = int64(u)View on GitHub (pinned to 909b515798)
Solutions
- Ensure the Mask length matches the IP family: use net.CIDRMask(ones, 32) for IPv4 and net.CIDRMask(ones, 128) for IPv6
- Parse CIDR strings with net.ParseCIDR instead of hand-building net.IPNet so Mask/IP stay consistent
- Check the wrapped error: the last-address length printed there reveals the mismatch
- For custom ranges, call network.IP.To4()/To16() first and derive the mask from the same representation
Example fix
// before
ipnet := net.IPNet{IP: net.ParseIP("2001:db8::"), Mask: net.CIDRMask(24, 32)} // 4-byte mask on IPv6
_, _, _, _, _, err := types.Range2Ints(ipnet)
// after
ipnet := net.IPNet{IP: net.ParseIP("2001:db8::"), Mask: net.CIDRMask(64, 128)}
_, _, _, _, _, err := types.Range2Ints(ipnet) Defensive patterns
Strategy: validation
Validate before calling
func maskMatchesIP(n net.IPNet) bool {
if n.IP.To4() != nil { return len(n.Mask) == net.IPv4len }
return len(n.Mask) == net.IPv6len
} Type guard
func consistentIPNet(n net.IPNet) bool { return (n.IP.To4() != nil) == (len(n.Mask) == net.IPv4len) } Prevention
- Derive masks with net.CIDRMask(ones, 32) for IPv4 and net.CIDRMask(ones, 128) for IPv6
- Never mix To4() IPs with 16-byte masks or vice versa
- Prefer string parsing (ParseCIDR) over hand-built IPNet structs
When it happens
Trigger: Range2Ints (or Addr2Ints with a CIDR string) receiving a net.IPNet whose Mask is the wrong length for its IP (e.g. a 4-byte mask on a 16-byte IPv6 IP), causing LastAddress to build a malformed/short net.IP that IP2Ints rejects.
Common situations: Manually constructing net.IPNet with mismatched IP/Mask lengths (mixing To4 IPs with 16-byte masks or vice versa); migrating code from IPv4-only assumptions to IPv6 networks; deserialized/persisted IPNet values with corrupted fields.
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
- converting first ip in range: %w
- while parsing capi whitelist file '%s': %w
- invalid ip range '%s': %w
- invalid ip address '%s'
- invalid ip address '%s': %w
AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06).
Data as JSON: /api/errors/a9ec354bd8062d1a.
Report an issue: GitHub.