{"record":{"id":"cb7cec0a0fe37823","repo":"AdguardTeam/AdGuardHome","slug":"start-is-greater-than-or-equal-to-end","errorCode":null,"errorMessage":"start is greater than or equal to end","messagePattern":"start is greater than or equal to end","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dhcpd/iprange.go","lineNumber":44,"sourceCode":"// maxRangeLen is the maximum IP range length.  The bitsets used in servers only\n// accept uints, which can have the size of 32 bit.\nconst maxRangeLen = math.MaxUint32\n\n// newIPRange creates a new IP address range.  start must be less than end.  The\n// resulting range must not be greater than maxRangeLen.\nfunc newIPRange(start, end net.IP) (r *ipRange, err error) {\n\tdefer func() { err = errors.Annotate(err, \"invalid ip range: %w\") }()\n\n\t// Make sure that both are 16 bytes long to simplify handling in\n\t// methods.\n\tstart, end = start.To16(), end.To16()\n\n\tstartInt := (&big.Int{}).SetBytes(start)\n\tendInt := (&big.Int{}).SetBytes(end)\n\tdiff := (&big.Int{}).Sub(endInt, startInt)\n\n\tif diff.Sign() <= 0 {\n\t\treturn nil, fmt.Errorf(\"start is greater than or equal to end\")\n\t} else if !diff.IsUint64() || diff.Uint64() > maxRangeLen {\n\t\treturn nil, fmt.Errorf(\"range is too large\")\n\t}\n\n\tr = &ipRange{\n\t\tstart: startInt,\n\t\tend:   endInt,\n\t}\n\n\treturn r, nil\n}\n\n// contains returns true if r contains ip.\nfunc (r *ipRange) contains(ip net.IP) (ok bool) {\n\tif r == nil {\n\t\treturn false\n\t}\n","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/dhcpd/iprange.go#L26-L62","documentation":"Returned by newIPRange when the DHCP range's start address is greater than or equal to its end address (compared as big-endian byte slices converted to big.Int). A valid range must be strictly increasing. This surfaces either directly from range validation or wrapped as 'bad dhcpv4/dhcpv6 configuration' from the HTTP API.","triggerScenarios":"Setting range_start >= range_end in a DHCPv4 or DHCPv6 config; transposing octets (192.168.1.200 as start, 192.168.1.100 as end); DHCPv6 pairs where the low 64 bits of start exceed those of end.","commonSituations":"Transposed octets when hand-editing YAML/JSON configs; misunderstanding that end is exclusive-of-equal; migrating a config where start/end fields got swapped; unit tests feeding reversed pairs.","solutions":["Swap the values so start < end (compare octet by octet or with python3 -c 'import ipaddress; print(ipaddress.IPv4Address(a) < ipaddress.IPv4Address(b))')","Add client-side validation before submitting the config","For IPv6 /64 ranges, verify only host bits differ and start's host bits are lower"],"exampleFix":"// before\n\"range_start\":\"192.168.1.200\",\"range_end\":\"192.168.1.100\"\n// -> start is greater than or equal to end\n\n// after\n\"range_start\":\"192.168.1.100\",\"range_end\":\"192.168.1.200\"","handlingStrategy":"validation","validationCode":"func rangeOrdered(start, end string) bool {\n\ts, e := net.ParseIP(start), net.ParseIP(end)\n\treturn s != nil && e != nil && bytes.Compare(s.To16(), e.To16()) < 0\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always validate start < end client-side before submitting","Compare with ipaddress (Python) or net.ParseIP byte comparison, not string compare","Watch for transposed octets when hand-editing configs"],"tags":["dhcp","validation","ip-range","configuration"],"backgroundTag":"invalid-ip-range","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}