{"record":{"id":"9840bb63f5c284a7","repo":"kubernetes/kops","slug":"could-not-determine-the-zone-of-subnet-q-specify","errorCode":null,"errorMessage":"could not determine the zone of subnet %q; specify the zone in the cluster spec","messagePattern":"could not determine the zone of subnet %q; specify the zone in the cluster spec","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/subnets.go","lineNumber":112,"sourceCode":"\t\t\t\t} else if subnet.CIDR != cloudSubnet.CIDR {\n\t\t\t\t\treturn fmt.Errorf(\"Subnet %q has configured CIDR %q, but the actual CIDR found was %q\", subnet.ID, subnet.CIDR, cloudSubnet.CIDR)\n\t\t\t\t}\n\n\t\t\t\tif needZones && subnet.Zone == \"\" {\n\t\t\t\t\tsubnet.Zone = cloudSubnet.Zone\n\t\t\t\t} else if subnet.Zone != cloudSubnet.Zone {\n\t\t\t\t\treturn fmt.Errorf(\"Subnet %q has configured Zone %q, but the actual Zone found was %q\", subnet.ID, subnet.Zone, cloudSubnet.Zone)\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\t}\n\n\tif needZones {\n\t\tfor i := range c.Spec.Networking.Subnets {\n\t\t\tsubnet := &c.Spec.Networking.Subnets[i]\n\t\t\tif subnet.ID != \"\" && subnet.Zone == \"\" {\n\t\t\t\treturn fmt.Errorf(\"could not determine the zone of subnet %q; specify the zone in the cluster spec\", subnet.Name)\n\t\t\t}\n\t\t}\n\t}\n\n\tif allSubnetsHaveCIDRs(c) {\n\t\tklog.V(4).Infof(\"All subnets have CIDRs; skipping assignment logic\")\n\t\treturn nil\n\t}\n\n\t_, cidr, err := net.ParseCIDR(c.Spec.Networking.NetworkCIDR)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Invalid NetworkCIDR: %q\", c.Spec.Networking.NetworkCIDR)\n\t}\n\n\t// We split the network range into 2, 4 or 8 subnets\n\t// But we then reserve the lowest one for the private block\n\t// (and we split _that_ into 8 further subnets, leaving the first one unused/for future use)\n","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/subnets.go#L94-L130","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nsubnets:\n- name: us-east-1a\n  id: subnet-0abc\n// after\nsubnets:\n- name: us-east-1a\n  id: subnet-0abc\n  zone: us-east-1a","handlingStrategy":"validation","validationCode":"for _, s := range spec.Networking.Subnets {\n    if s.ID != \"\" && s.Zone == \"\" {\n        return fmt.Errorf(\"subnet %s has an ID but no zone; set zone explicitly\", s.Name)\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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."],"tags":["subnet","zones","aws","cluster-provisioning"],"backgroundTag":"subnet-zone-unknown","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}