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

  1. Ensure the Mask length matches the IP family: use net.CIDRMask(ones, 32) for IPv4 and net.CIDRMask(ones, 128) for IPv6
  2. Parse CIDR strings with net.ParseCIDR instead of hand-building net.IPNet so Mask/IP stay consistent
  3. Check the wrapped error: the last-address length printed there reveals the mismatch
  4. 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

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


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/a9ec354bd8062d1a. Report an issue: GitHub.