kubernetes/kops · error

cannot mix egress values in private or IPv6-capable subnets

Error message

cannot mix egress values in private or IPv6-capable subnets

What it means

During AWS network model building, kops groups NAT-capable subnets per zone and takes the Egress value from the first subnet as the zone-wide setting. If any other subnet in that zone declares a different egress value, the builder aborts because it cannot provision one egress path (NAT gateway, NAT instance, Transit Gateway, etc.) per zone with conflicting per-subnet settings. This is a cluster-spec validation error raised at `kops update cluster` model-render time, not an AWS API error.

Source

Thrown at pkg/model/awsmodel/network.go:432

		egress := info.NATSubnets[0].Egress
		publicIP := info.NATSubnets[0].PublicIP

		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,

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Open the cluster spec and make the `egress` field identical for every private/IPv6-capable subnet within the same zone (leave egress empty on all of them for kops-managed NAT gateways).
  2. If per-zone egress is genuinely needed, move the differing subnets into a different zone, since the check is per-zone (infoByZone).
  3. Run `kops edit cluster` (or `kops replace -f`) with the corrected spec, then `kops update cluster` again.
  4. If you intentionally want mixed egress, split the cluster or file a feature request — the builder explicitly does not support mixed values (see comment at network.go:429).

Example fix

# before (cluster.yaml, same zone)
subnets:
- name: us-east-1a-private
  zone: us-east-1a
  type: Private
  egress: nat-0abc123
- name: us-east-1a-private2
  zone: us-east-1a
  type: Private
  egress: External
# after
subnets:
- name: us-east-1a-private
  zone: us-east-1a
  type: Private
  egress: nat-0abc123
- name: us-east-1a-private2
  zone: us-east-1a
  type: Private
  egress: nat-0abc123
Defensive patterns

Strategy: validation

Validate before calling

#!/bin/bash
# Run before `kops update cluster`: ensure all private subnets per zone share one egress value
kops get cluster -oyaml | awk '
  /zone:/ {zone=$2} /egress:/ {print zone, $2}' | sort -u |
  awk '{if (seen[$1] && seen[$1]!=$2) {print "CONFLICT in zone", $1; exit 1} seen[$1]=$2}'

Type guard

func consistentEgress(subnets []kops.ClusterSubnetSpec, zone string) bool {
    seen := map[string]bool{}
    for _, s := range subnets {
        if s.Zone != zone { continue }
        seen[s.Egress] = true
        if len(seen) > 1 { return false }
    }
    return true
}

Try / catch

err := updateCluster(ctx)
if err != nil && strings.Contains(err.Error(), "cannot mix egress values") {
    // normalize egress across subnets in the zone, then retry once
}

Prevention

When it happens

Trigger: Running `kops update cluster` when two or more subnets in the same zone that route through NAT (private or IPv6-capable subnets) specify different `egress` values in cluster.spec.networkID/subnets config — e.g. one subnet with egress: nat-xxxx and another with egress: External, or one with an eipalloc- ID and another empty.

Common situations: Hand-editing the cluster spec to give one private subnet a Transit Gateway egress while siblings still use the default NAT gateway; migrating a cluster gradually from NAT gateways to NAT instances and changing only some subnets; copy-pasting subnet blocks between zones/zones with differing egress fields.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/a608c9dac574f4b3. Report an issue: GitHub.