{"record":{"id":"7e614c12a2c09c87","repo":"crowdsecurity/crowdsec","slug":"inconsistent-size-for-range-first-d-and-last-d","errorCode":null,"errorMessage":"inconsistent size for range first(%d) and last(%d) ip","messagePattern":"inconsistent size for range first\\((.+?)\\) and last\\((.+?)\\) ip","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/types/ip.go","lineNumber":75,"sourceCode":"\treturn sz, start, end, start, end, nil\n}\n\n/*size (16|4), nw_start, suffix_start, nw_end, suffix_end, error*/\nfunc Range2Ints(network net.IPNet) (int, int64, int64, int64, int64, error) {\n\tszStart, nwStart, sfxStart, err := IP2Ints(network.IP)\n\tif err != nil {\n\t\treturn -1, 0, 0, 0, 0, fmt.Errorf(\"converting first ip in range: %w\", err)\n\t}\n\n\tlastAddr := LastAddress(network)\n\n\tszEnd, nwEnd, sfxEnd, err := IP2Ints(lastAddr)\n\tif err != nil {\n\t\treturn -1, 0, 0, 0, 0, fmt.Errorf(\"transforming last address of range: %w\", err)\n\t}\n\n\tif szEnd != szStart {\n\t\treturn -1, 0, 0, 0, 0, fmt.Errorf(\"inconsistent size for range first(%d) and last(%d) ip\", szStart, szEnd)\n\t}\n\n\treturn szStart, nwStart, sfxStart, nwEnd, sfxEnd, nil\n}\n\nfunc uint2int(u uint64) int64 {\n\tvar ret int64\n\tif u == math.MaxInt64 {\n\t\tret = 0\n\t} else if u == math.MaxUint64 {\n\t\tret = math.MaxInt64\n\t} else if u > math.MaxInt64 {\n\t\tu -= math.MaxInt64\n\t\tret = int64(u)\n\t} else {\n\t\tret = int64(u)\n\t\tret -= math.MaxInt64\n\t}","sourceCodeStart":57,"sourceCodeEnd":93,"githubUrl":"https://github.com/crowdsecurity/crowdsec/blob/909b5157986a2b2c2163300fdaef5ed01289f7d2/pkg/types/ip.go#L57-L93","documentation":"Range2Ints requires the first and last addresses of the range to have the same size class (4 for IPv4, 16 for IPv6). If IP2Ints returns different sizes for the network base and the broadcast address, this error is thrown. It signals a net.IPNet whose IP and Mask encode inconsistent families, so the range cannot be represented as a uniform integer span.","triggerScenarios":"Range2Ints (or Addr2Ints with a CIDR) with a net.IPNet whose base IP normalizes to 4 bytes while the ORed host-mask address normalizes to 16 bytes (or vice versa) — i.e. mixed IPv4/IPv6 fields in one net.IPNet.","commonSituations":"Hand-built net.IPNet where IP is a 4-byte representation but the mask indexing produced a 16-byte result; code paths that convert only one endpoint with To4(); corrupted IPNet values from external data.","solutions":["Keep both endpoints in the same family: call network.IP.To4() and use a 4-byte mask for IPv4, To16()/CIDRMask(n,128) for IPv6","Parse CIDRs with net.ParseCIDR rather than constructing net.IPNet manually","Log the two sizes from the message to identify which field is the wrong family","Reject such IPNet values at the configuration-parsing boundary before numeric conversion"],"exampleFix":"// before\nipnet := net.IPNet{IP: net.ParseIP(\"192.168.1.0\").To4(), Mask: net.CIDRMask(24, 128)}\n_, _, _, _, _, err := types.Range2Ints(ipnet) // inconsistent size 4 vs 16\n// after\nipnet := net.IPNet{IP: net.ParseIP(\"192.168.1.0\").To4(), Mask: net.CIDRMask(24, 32)}","handlingStrategy":"validation","validationCode":"func sameFamilyEndpoints(n net.IPNet) bool {\n    last := types.LastAddress(n)\n    return (n.IP.To4() != nil) == (last.To4() != nil)\n}","typeGuard":"func uniformFamily(n net.IPNet) bool { return n.IP.To4() != nil && types.LastAddress(n).To4() != nil || n.IP.To4() == nil }","tryCatchPattern":null,"preventionTips":["Normalize both endpoints with the same To4()/To16() call before converting","Construct IPNet values with matching family for IP and Mask","Reject mixed-family CIDRs during input parsing"],"tags":["ip","cidr","ipv6","type-mismatch"],"backgroundTag":"invalid-argument-value","analyzedSha":"909b5157986a2b2c2163300fdaef5ed01289f7d2","analyzedAt":"2026-09-06T12:27:26.012Z","contentChangedAt":"2026-09-06T12:27:26.012Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}