kubernetes/kops · error
cannot mix publicIP values in private or IPv6-capable subnet
Error message
cannot mix publicIP values in private or IPv6-capable subnets
What it means
The same per-zone consistency check in the AWS network builder also requires every NAT-routing subnet in a zone to share the same `publicIP` value (an explicitly requested Elastic IP allocation for the zone's NAT gateway). If subnets in one zone declare different `publicIP` values, the builder cannot decide which EIP to associate and fails. Raised at model-build time during `kops update cluster`.
Source
Thrown at pkg/model/awsmodel/network.go:435
allUnmanaged := true
for _, subnetSpec := range info.NATSubnets {
if !isUnmanaged(subnetSpec) {
allUnmanaged = false
}
}
if allUnmanaged {
klog.V(4).Infof("skipping network configuration in zone %s - all subnets unmanaged", zone)
continue
}
// Verify we don't have mixed values for egress/publicIP - the code doesn't handle it
for _, subnet := range info.NATSubnets {
if subnet.Egress != egress {
return fmt.Errorf("cannot mix egress values in private or IPv6-capable subnets")
}
if subnet.PublicIP != publicIP {
return fmt.Errorf("cannot mix publicIP values in private or IPv6-capable subnets")
}
}
var ngw *awstasks.NatGateway
var tgwID *string
var in *awstasks.Instance
if egress != "" {
if strings.HasPrefix(egress, "nat-") {
ngw = &awstasks.NatGateway{
Name: new(zone + "." + b.ClusterName()),
Lifecycle: b.Lifecycle,
Subnet: egressSubnet,
ID: new(egress),
AssociatedRouteTable: egressRouteTable,
// If we're here, it means this NatGateway was specified, so we are Shared
Shared: new(true),
Tags: b.CloudTags(zone+"."+b.ClusterName(), true),View on GitHub (pinned to 4c8573c808)
Solutions
- Make `publicIP` identical (all set to the same EIP, or all empty) for every private/IPv6 subnet in the affected zone.
- To reuse one EIP per zone, set it on every subnet spec in that zone, not just the first.
- Apply via `kops replace -f cluster.yaml` or `kops edit cluster`, then re-run `kops update cluster`.
- If you need distinct EIPs per subnet, split the subnets across zones — the check is per-zone.
Example fix
# before - name: us-east-1a-private type: Private zone: us-east-1a publicIP: eipalloc-0aaa - name: us-east-1a-private2 type: Private zone: us-east-1a publicIP: eipalloc-0bbb # after - name: us-east-1a-private type: Private zone: us-east-1a publicIP: eipalloc-0aaa - name: us-east-1a-private2 type: Private zone: us-east-1a publicIP: eipalloc-0aaa
Defensive patterns
Strategy: validation
Validate before calling
#!/bin/bash # Fail fast if publicIP values differ within a zone kops get cluster -oyaml | yq '.spec.subnets | group_by(.zone) | .[] | select((map(.publicIP // "") | unique | length) > 1) | .[0].zone' | grep . && echo "mixed publicIP in zone" && exit 1 || true
Type guard
func uniformPublicIPPerZone(subnets []kops.ClusterSubnetSpec) bool {
m := map[string]struct{}{}
for _, s := range subnets {
m[s.Zone+"|"+s.PublicIP] = struct{}{}
}
zones := map[string]struct{}{}
for k := range m {
zones[strings.SplitN(k, "|", 2)[0]] = struct{}{}
}
return len(m) == len(zones)
} Try / catch
err := updateCluster(ctx)
if err != nil && strings.Contains(err.Error(), "cannot mix publicIP values") {
// set the same publicIP on every private subnet in the offending zone, then re-run
} Prevention
- When reusing a pre-created EIP for a zone, set publicIP on EVERY private subnet block in that zone.
- Keep publicIP empty everywhere and let kops allocate/track Elastic IPs unless reuse is required.
- Add a spec-lint step (yq/jq script) to CI that asserts one publicIP per zone.
- Document EIP reuse in your cluster template so operators don't annotate only some subnets.
When it happens
Trigger: `kops update cluster` where two or more private/IPv6-capable subnets in the same zone specify different `publicIP` fields (e.g. one set to an existing EIP allocation string and another left empty or set to a different EIP).
Common situations: Reusing pre-created Elastic IPs across a zone but forgetting to set publicIP on every subnet block; templating that injects publicIP only into some subnets; adopting an existing cluster and annotating only part of the subnets.
Related errors
- cannot mix egress values in private or IPv6-capable subnets
- multiple physical network interfaces found with MAC address
- cannot determine challenge endpoint for instance id: %s
- unhandled LoadBalancer type %q
- subnet %q had unknown type %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/5a1af43596d9eb3f.
Report an issue: GitHub.