{"record":{"id":"6c901a21049c6ff4","repo":"cilium/cilium","slug":"failed-to-set-reserved-ranges-for-cidr-s-w","errorCode":null,"errorMessage":"failed to set reserved ranges for CIDR %s: %w","messagePattern":"failed to set reserved ranges for CIDR (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"operator/pkg/ipam/allocator/multipool/pool_allocator.go","lineNumber":309,"sourceCode":"\tfor i := range cidrs {\n\t\tcidrConfig := &cidrs[i]\n\t\tprefixes = append(prefixes, cidrConfig.cidr)\n\t}\n\n\treturn prefixes\n}\n\nfunc setReservedRanges(allocators []cidralloc.CIDRAllocator, cidrs []poolCIDRConfig) error {\n\treservedRanges := make(map[netip.Prefix][]netipx.IPRange, len(cidrs))\n\tfor i := range cidrs {\n\t\tcidrConfig := &cidrs[i]\n\t\treservedRanges[cidrConfig.cidr] = cidrConfig.reservedRanges\n\t}\n\n\tfor i := range allocators {\n\t\tprefix := allocators[i].Prefix()\n\t\tif err := allocators[i].SetReservedRanges(reservedRanges[prefix]); err != nil {\n\t\t\treturn fmt.Errorf(\"failed to set reserved ranges for CIDR %s: %w\", prefix, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc (p *PoolAllocator) UpsertPool(poolName string, ipv4CIDRs []poolCIDRConfig, ipv4MaskSize int, ipv6CIDRs []poolCIDRConfig, ipv6MaskSize int, opts ...PoolOption) error {\n\tp.mutex.Lock()\n\tdefer p.mutex.Unlock()\n\n\tvar options poolOptions\n\tfor _, opt := range opts {\n\t\topt(&options)\n\t}\n\n\tpool, exists := p.pools[poolName]\n\tif exists && ipv4MaskSize != pool.v4MaskSize {\n\t\treturn fmt.Errorf(\"cannot change IPv4 mask size in existing pool %q\", poolName)","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/cilium/cilium/blob/ac7b90affa4baf0642e6685319d56907b3a73a6d/operator/pkg/ipam/allocator/multipool/pool_allocator.go#L291-L327","documentation":"setReservedRanges configures each pool allocator with reserved IP ranges (e.g. the node/service-excluded ranges) by calling SetReservedRanges on every CIDRAllocator of the pool, invoked from UpsertPool. When an allocator rejects the ranges, the error is wrapped with the offending CIDR prefix. This usually means the reserved ranges do not fit or validate within that allocator's CIDR.","triggerScenarios":"UpsertPool is called with a CiliumPodIPPool whose reservedRanges (per-CIDR) are invalid for the allocator's prefix — e.g. a reserved range not contained in the pool CIDR, a range whose start/end are inverted, misformatted IPs, or reserved ranges supplied for a CIDR that is not part of the pool.","commonSituations":"Typo or wrong subnet in the pool's reservedRanges spec; reserved ranges defined per-CIDR don't match the allocator prefix after a CIDR edit; IPv4/IPv6 values swapped in the pool spec; overlapping/inverted ranges (first > last) failing validation.","solutions":["Validate the pool's reservedRanges in the CiliumPodIPPool spec: each range must be inside the matching pool CIDR, with start <= end and valid IPs of the same family.","Compare the prefix printed in the error against the reservedRanges map key — fix the mismatched CIDR entry in the pool spec.","Re-apply a known-good CiliumPodIPPool (kubectl get ciliumpodippool <name> -o yaml, correct, kubectl apply) so UpsertPool succeeds on the next sync.","If ranges come from config/helm values, fix the values and upgrade rather than editing the object ad hoc, to avoid drift on the next sync."],"exampleFix":"// before: reserved range outside pool CIDR\ncidrs:\n- cidr: \"10.0.0.0/16\"\n  reservedRanges: [{\"start\": \"192.168.1.1\", \"end\": \"192.168.1.10\"}]\n// after: range contained in the pool CIDR\ncidrs:\n- cidr: \"10.0.0.0/16\"\n  reservedRanges: [{\"start\": \"10.0.0.1\", \"end\": \"10.0.0.10\"}]","handlingStrategy":"validation","validationCode":"// validate pool reserved ranges before UpsertPool\nfor _, cc := range cidrConfigs {\n\tprefix := netip.MustParsePrefix(cc.cidr)\n\tfor _, r := range cc.reservedRanges {\n\t\tstart, end := netip.MustParseAddr(r.Start), netip.MustParseAddr(r.End)\n\t\tif !prefix.Contains(start) || !prefix.Contains(end) || start.Compare(end) > 0 {\n\t\t\treturn fmt.Errorf(\"reserved range %s-%s invalid for %s\", r.Start, r.End, cc.cidr)\n\t\t}\n\t}\n}","typeGuard":"func reservedRangeValid(prefix netip.Prefix, start, end netip.Addr) bool {\n\treturn prefix.Contains(start) && prefix.Contains(end) && start.Compare(end) <= 0\n}","tryCatchPattern":"if err := p.UpsertPool(ctx, pool); err != nil {\n\tif strings.Contains(err.Error(), \"failed to set reserved ranges\") {\n\t\tlog.Error(\"fix CiliumPodIPPool reservedRanges (must be inside pool CIDR, start<=end)\", \"err\", err)\n\t}\n\treturn err\n}","preventionTips":["Validate reservedRanges containment/inversion in a webhook or before apply.","Keep reserved ranges and pool CIDRs defined together in one spec to avoid drift.","Match IP family: don't put IPv4 reserved ranges under an IPv6 CIDR entry."],"tags":["ipam","cidr","cilium","configuration","validation"],"backgroundTag":"reserved-range-validation-failed","analyzedSha":"ac7b90affa4baf0642e6685319d56907b3a73a6d","analyzedAt":"2026-08-31T18:27:15.868Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}