{"record":{"id":"89daadba993f280b","repo":"AdguardTeam/AdGuardHome","slug":"lease-s-s-out-of-range-not-adding","errorCode":null,"errorMessage":"lease %s (%s) out of range, not adding","messagePattern":"lease (.+?) \\((.+?)\\) out of range, not adding","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dhcpd/v4_unix.go","lineNumber":329,"sourceCode":"\t}\n\n\treturn nil\n}\n\n// addLease adds a dynamic or static lease.\nfunc (s *v4Server) addLease(l *dhcpsvc.Lease) (err error) {\n\tr := s.conf.ipRange\n\tleaseIP := net.IP(l.IP.AsSlice())\n\toffset, inOffset := r.offset(leaseIP)\n\n\tif l.IsStatic {\n\t\t// TODO(a.garipov, d.seregin): Subnet can be nil when dhcp server is\n\t\t// disabled.\n\t\tif sn := s.conf.subnet; !sn.Contains(l.IP) {\n\t\t\treturn fmt.Errorf(\"subnet %s does not contain the ip %q\", sn, l.IP)\n\t\t}\n\t} else if !inOffset {\n\t\treturn fmt.Errorf(\"lease %s (%s) out of range, not adding\", l.IP, l.HWAddr)\n\t}\n\n\t// TODO(e.burkov):  l must have a valid hostname here, investigate.\n\tif l.Hostname != \"\" {\n\t\tif _, ok := s.hostsIndex[l.Hostname]; ok {\n\t\t\treturn fmt.Errorf(\"hostname: %w\", errors.ErrDuplicated)\n\t\t}\n\n\t\ts.hostsIndex[l.Hostname] = l\n\t}\n\ts.ipIndex[l.IP] = l\n\n\ts.leases = append(s.leases, l)\n\ts.leasedOffsets.set(offset, true)\n\n\treturn nil\n}\n","sourceCodeStart":311,"sourceCodeEnd":347,"githubUrl":"https://github.com/AdguardTeam/AdGuardHome/blob/b41aefbe51c8dde65e2c50f093996afa0502edf9/internal/dhcpd/v4_unix.go#L311-L347","documentation":"addLease rejects a dynamic lease whose IP is not within the server's dynamic address offset range (the pool between the configured offset start and end). Dynamic (non-static) leases must fall inside the allocatable pool; otherwise they are considered out of range and refused.","triggerScenarios":"ResetLeases, reserveLease, or handleDecline tries to add a dynamic lease with an IP outside the configured offset range — typically after shrinking the DHCP range while persisted leases still reference old IPs.","commonSituations":"Shrinking the DHCP pool range while the lease database still contains leases in the removed range; restoring a lease dump onto a server with a different/smaller range; race where the range changed after the IP was picked.","solutions":["Widen the DHCP range back to cover the stored leases","Clear/reset the leases table so stale out-of-range leases are dropped","Reconcile the lease store whenever the DHCP range configuration changes"],"exampleFix":"// before\nrange_start: 192.168.1.100\nrange_end: 192.168.1.120 // leases at .150 now out of range\n\n// after\nrange_end: 192.168.1.200 // or clear stored leases","handlingStrategy":"validation","validationCode":"// check pool membership before persisting dynamic leases\noffset, ok := r.offset(leaseIP)\nif !ok { /* drop the stale lease instead of re-adding */ }","typeGuard":null,"tryCatchPattern":"// ignore out-of-range errors when resetting leases\neverythingElse, _ := srv.ResetLeases(leases) // or filter leases first","preventionTips":["Filter persisted leases against the current pool before ResetLeases","Clear lease stores when shrinking the DHCP range","Keep range changes and lease resets in one config transaction"],"tags":["dhcp","dynamic-lease","ip-range","validation","ipv4"],"backgroundTag":"ip-out-of-dhcp-pool","analyzedSha":"b41aefbe51c8dde65e2c50f093996afa0502edf9","analyzedAt":"2026-08-27T04:57:55.097Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}