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
- Add an explicit `zone` to each subnet entry in the cluster spec, then re-run `kops update cluster`.
- Ensure `spec.networking.networkID` is set so kOps can query the VPC and derive zones.
- 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
- Always set an explicit zone for subnets referenced by ID.
- Set spec.networking.networkID so kOps can resolve zones from the VPC.
- Grant ec2:DescribeSubnets to kOps credentials.
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
- Subnet %q has configured Zone %q, but the actual Zone found
- subnet %q had unknown type %q
- subnet %q had unknown type %q
- could not find public subnet in zone: %q
- found multiple public subnets in zone: %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/9840bb63f5c284a7.
Report an issue: GitHub.