kubernetes/kubernetes · error
usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-siz
Error message
usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 is not allowed if --node-cidr-mask-size is set. For dual-stack clusters please unset it and use IPFamily specific flags
What it means
In single-stack mode the legacy --node-cidr-mask-size is authoritative and is mutually exclusive with the family-specific --node-cidr-mask-size-ipv4 / -ipv6 flags. KCM's setNodeCIDRMaskSizes rejects setting any family flag alongside the legacy one to avoid contradictory config.
Source
Thrown at cmd/kube-controller-manager/app/core.go:944
if cfg.NodeCIDRMaskSizeIPv4 != 0 {
ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4)
}
if cfg.NodeCIDRMaskSizeIPv6 != 0 {
ipv6Mask = int(cfg.NodeCIDRMaskSizeIPv6)
}
return sortedSizes(ipv4Mask, ipv6Mask), nil
}
maskConfigured := cfg.NodeCIDRMaskSize != 0
maskV4Configured := cfg.NodeCIDRMaskSizeIPv4 != 0
maskV6Configured := cfg.NodeCIDRMaskSizeIPv6 != 0
isSingleStackIPv6 := netutils.IsIPv6CIDR(clusterCIDRs[0])
// original flag is set
if maskConfigured {
// original mask flag is still the main reference.
if maskV4Configured || maskV6Configured {
return nil, errors.New("usage of --node-cidr-mask-size-ipv4 and --node-cidr-mask-size-ipv6 is not allowed if --node-cidr-mask-size is set. For dual-stack clusters please unset it and use IPFamily specific flags")
}
mask := int(cfg.NodeCIDRMaskSize)
return sortedSizes(mask, mask), nil
}
if maskV4Configured {
if isSingleStackIPv6 {
return nil, errors.New("usage of --node-cidr-mask-size-ipv4 is not allowed for a single-stack IPv6 cluster")
}
ipv4Mask = int(cfg.NodeCIDRMaskSizeIPv4)
}
// !maskV4Configured && !maskConfigured && maskV6Configured
if maskV6Configured {
if !isSingleStackIPv6 {
return nil, errors.New("usage of --node-cidr-mask-size-ipv6 is not allowed for a single-stack IPv4 cluster")View on GitHub (pinned to b882c60b40)
Solutions
- Keep only --node-cidr-mask-size (single-stack), or unset it and keep the family-specific flags.
- Lint the final flag set to ensure the legacy and family flags are not both present.
Example fix
# before --node-cidr-mask-size=24 --node-cidr-mask-size-ipv6=64 # after --node-cidr-mask-size=24
Defensive patterns
Strategy: validation
Validate before calling
maskConfigured := cfg.NodeCIDRMaskSize != 0
if maskConfigured && (cfg.NodeCIDRMaskSizeIPv4 != 0 || cfg.NodeCIDRMaskSizeIPv6 != 0) {
return errors.New("--node-cidr-mask-size is mutually exclusive with v4/v6 mask flags")
} Type guard
func mutuallyExclusiveMasksSet(cfg nodeipamconfig.NodeIPAMControllerConfiguration) bool {
return cfg.NodeCIDRMaskSize != 0 && (cfg.NodeCIDRMaskSizeIPv4 != 0 || cfg.NodeCIDRMaskSizeIPv6 != 0)
} Prevention
- Finish migrating off the legacy mask flag before introducing family flags.
- Lint the union of all mask flags in rendered manifests.
When it happens
Trigger: Single cluster CIDR, cfg.NodeCIDRMaskSize != 0 AND (NodeCIDRMaskSizeIPv4 != 0 OR NodeCIDRMaskSizeIPv6 != 0). core.go:941-944.
Common situations: Flag migration leaving both old and new set; chart defaults that populate all mask flags; merging configs from different sources.
Related errors
- --cidr-allocator-type is set to 'CloudAllocator' but cloud p
- usage of --node-cidr-mask-size is not allowed with dual-stac
- usage of --node-cidr-mask-size-ipv4 is not allowed for a sin
- usage of --node-cidr-mask-size-ipv6 is not allowed for a sin
- --cidr-allocator-type is set to 'CloudAllocator' but cloud p
AI-assisted analysis of kubernetes/kubernetes@b882c60b40 (2026-08-07).
Data as JSON: /api/errors/3dc767986c161017.
Report an issue: GitHub.