kubernetes/kops · error

could not determine the zone of subnet %q; specify the zone

Error message

could not determine the zone of subnet %q; specify the zone in the cluster spec

What it means

For AWS clusters, kOps tries to fill in the zone of any subnet referenced by ID from the cloud. If after lookup a subnet still has no zone (the cloud returned no zone information), kOps cannot place instances in it and asks the user to specify the zone explicitly in the cluster spec.

Source

Thrown at upup/pkg/fi/cloudup/subnets.go:112

				} else if subnet.CIDR != cloudSubnet.CIDR {
					return fmt.Errorf("Subnet %q has configured CIDR %q, but the actual CIDR found was %q", subnet.ID, subnet.CIDR, cloudSubnet.CIDR)
				}

				if needZones && subnet.Zone == "" {
					subnet.Zone = cloudSubnet.Zone
				} else if subnet.Zone != cloudSubnet.Zone {
					return fmt.Errorf("Subnet %q has configured Zone %q, but the actual Zone found was %q", subnet.ID, subnet.Zone, cloudSubnet.Zone)
				}

			}
		}
	}

	if needZones {
		for i := range c.Spec.Networking.Subnets {
			subnet := &c.Spec.Networking.Subnets[i]
			if subnet.ID != "" && subnet.Zone == "" {
				return fmt.Errorf("could not determine the zone of subnet %q; specify the zone in the cluster spec", subnet.Name)
			}
		}
	}

	if allSubnetsHaveCIDRs(c) {
		klog.V(4).Infof("All subnets have CIDRs; skipping assignment logic")
		return nil
	}

	_, cidr, err := net.ParseCIDR(c.Spec.Networking.NetworkCIDR)
	if err != nil {
		return fmt.Errorf("Invalid NetworkCIDR: %q", c.Spec.Networking.NetworkCIDR)
	}

	// We split the network range into 2, 4 or 8 subnets
	// But we then reserve the lowest one for the private block
	// (and we split _that_ into 8 further subnets, leaving the first one unused/for future use)

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Add an explicit `zone` to each subnet entry in the cluster spec, then re-run `kops update cluster`.
  2. Ensure `spec.networking.networkID` is set so kOps can query the VPC and derive zones.
  3. Verify the credentials can describe subnets (ec2:DescribeSubnets) so the lookup returns zone data.

Example fix

// before
subnets:
- name: us-east-1a
  id: subnet-0abc
// after
subnets:
- name: us-east-1a
  id: subnet-0abc
  zone: us-east-1a
Defensive patterns

Strategy: validation

Validate before calling

for _, s := range spec.Networking.Subnets {
    if s.ID != "" && s.Zone == "" {
        return fmt.Errorf("subnet %s has an ID but no zone; set zone explicitly", s.Name)
    }
}

Prevention

When it happens

Trigger: Subnets specified by ID with no `zone` in the spec, and `cloud.FindVPCInfo` returned subnet info lacking a Zone (unusual cloud response, or the VPC lookup path was skipped because networkID was empty while subnets have IDs), leaving needZones unfulfilled.

Common situations: Shared-VPC clusters where subnet discovery is restricted; custom cloud implementations returning partial SubnetInfo; specs where networkID is unset so the ID->zone lookup loop at subnets.go:67-105 never ran.

Related errors


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