cilium/cilium · error
failed to set reserved ranges for CIDR %s: %w
Error message
failed to set reserved ranges for CIDR %s: %w
What it means
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.
Source
Thrown at operator/pkg/ipam/allocator/multipool/pool_allocator.go:309
for i := range cidrs {
cidrConfig := &cidrs[i]
prefixes = append(prefixes, cidrConfig.cidr)
}
return prefixes
}
func setReservedRanges(allocators []cidralloc.CIDRAllocator, cidrs []poolCIDRConfig) error {
reservedRanges := make(map[netip.Prefix][]netipx.IPRange, len(cidrs))
for i := range cidrs {
cidrConfig := &cidrs[i]
reservedRanges[cidrConfig.cidr] = cidrConfig.reservedRanges
}
for i := range allocators {
prefix := allocators[i].Prefix()
if err := allocators[i].SetReservedRanges(reservedRanges[prefix]); err != nil {
return fmt.Errorf("failed to set reserved ranges for CIDR %s: %w", prefix, err)
}
}
return nil
}
func (p *PoolAllocator) UpsertPool(poolName string, ipv4CIDRs []poolCIDRConfig, ipv4MaskSize int, ipv6CIDRs []poolCIDRConfig, ipv6MaskSize int, opts ...PoolOption) error {
p.mutex.Lock()
defer p.mutex.Unlock()
var options poolOptions
for _, opt := range opts {
opt(&options)
}
pool, exists := p.pools[poolName]
if exists && ipv4MaskSize != pool.v4MaskSize {
return fmt.Errorf("cannot change IPv4 mask size in existing pool %q", poolName)View on GitHub (pinned to ac7b90affa)
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.
Example fix
// before: reserved range outside pool CIDR
cidrs:
- cidr: "10.0.0.0/16"
reservedRanges: [{"start": "192.168.1.1", "end": "192.168.1.10"}]
// after: range contained in the pool CIDR
cidrs:
- cidr: "10.0.0.0/16"
reservedRanges: [{"start": "10.0.0.1", "end": "10.0.0.10"}] Defensive patterns
Strategy: validation
Validate before calling
// validate pool reserved ranges before UpsertPool
for _, cc := range cidrConfigs {
prefix := netip.MustParsePrefix(cc.cidr)
for _, r := range cc.reservedRanges {
start, end := netip.MustParseAddr(r.Start), netip.MustParseAddr(r.End)
if !prefix.Contains(start) || !prefix.Contains(end) || start.Compare(end) > 0 {
return fmt.Errorf("reserved range %s-%s invalid for %s", r.Start, r.End, cc.cidr)
}
}
} Type guard
func reservedRangeValid(prefix netip.Prefix, start, end netip.Addr) bool {
return prefix.Contains(start) && prefix.Contains(end) && start.Compare(end) <= 0
} Try / catch
if err := p.UpsertPool(ctx, pool); err != nil {
if strings.Contains(err.Error(), "failed to set reserved ranges") {
log.Error("fix CiliumPodIPPool reservedRanges (must be inside pool CIDR, start<=end)", "err", err)
}
return err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- not ready
- no cilium agent pods found
- unable to detect minimum Cilium version
- unable to initialize IPv4 allocator: %w
- cidr %s is not part of the requested pool
AI-assisted analysis of cilium/cilium@ac7b90affa (2026-08-31).
Data as JSON: /api/errors/6c901a21049c6ff4.
Report an issue: GitHub.