{"record":{"id":"94d3204fa832ad87","repo":"kubernetes/kops","slug":"instance-group-q-must-specify-exactly-one-zone","errorCode":null,"errorMessage":"instance group %q must specify exactly one zone","messagePattern":"instance group %q must specify exactly one zone","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/model/gcemodel/api_loadbalancer.go","lineNumber":174,"sourceCode":"\t\tLifecycle: b.Lifecycle,\n\t}\n\tc.AddTask(hc)\n\n\t// Collect ControlPlane and APIServer MIGs separately. The API backend service\n\t// includes both (both serve the kube-apiserver), while the kops-controller and\n\t// etcd backend services only include ControlPlane MIGs.\n\tvar apiIGMs []*gcetasks.InstanceGroupManager\n\tvar controlPlaneIGMs []*gcetasks.InstanceGroupManager // Currently these contain etcd instances\n\trequireEtcdLB := false\n\tfor _, ig := range b.InstanceGroups {\n\t\tif !ig.RunsAPIServer() {\n\t\t\tcontinue\n\t\t}\n\t\tif len(ig.Spec.Zones) > 1 {\n\t\t\treturn fmt.Errorf(\"instance group %q has %d zones, which is not yet supported for GCP\", ig.GetName(), len(ig.Spec.Zones))\n\t\t}\n\t\tif len(ig.Spec.Zones) == 0 {\n\t\t\treturn fmt.Errorf(\"instance group %q must specify exactly one zone\", ig.GetName())\n\t\t}\n\t\tzone := ig.Spec.Zones[0]\n\t\tigm := &gcetasks.InstanceGroupManager{Name: s(gce.NameForInstanceGroupManager(b.Cluster.ObjectMeta.Name, ig.ObjectMeta.Name, zone)), Zone: s(zone)}\n\t\tapiIGMs = append(apiIGMs, igm)\n\t\tif ig.IsControlPlane() {\n\t\t\tcontrolPlaneIGMs = append(controlPlaneIGMs, igm)\n\t\t} else if ig.IsAPIServerOnly() {\n\t\t\trequireEtcdLB = b.Cluster.UsesNoneDNS()\n\t\t} else {\n\t\t\treturn fmt.Errorf(\"instance group %q neither control-plane nor api-server\", ig.GetName())\n\t\t}\n\t}\n\tbackendService := &gcetasks.BackendService{\n\t\tName:                  s(b.NameForBackendService(\"api\")),\n\t\tProtocol:              s(\"TCP\"),\n\t\tHealthChecks:          []*gcetasks.HealthCheck{hc},\n\t\tLifecycle:             b.Lifecycle,\n\t\tLoadBalancingScheme:   s(\"INTERNAL\"),","sourceCodeStart":156,"sourceCodeEnd":192,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/pkg/model/gcemodel/api_loadbalancer.go#L156-L192","documentation":"Also in createInternalLB (pkg/model/gcemodel/api_loadbalancer.go:174): every instance group that runs the API server must specify exactly one zone for the GCE internal load balancer. When spec.zones is empty, kOps cannot determine which zone-level InstanceGroupManager to create and returns this error.","triggerScenarios":"An API-serving instance group (RunsAPIServer() == true) whose spec.zones array is missing or zero-length while building a GCP cluster with an internal API load balancer (e.g. api.loadBalancer.type internal or UsesNoneDNS).","commonSituations":"Hand-written instance group manifests that omit zones (relying on cluster-level defaults); tooling that generates IGs without per-IG zones on GCP; IGs created before zones were made mandatory for this code path.","solutions":["Add exactly one zone to the instance group: run 'kops edit ig <name>' and set spec.zones: [<zone>]","Ensure the zone matches one of the cluster's declared zones/subnets","If you intended multi-zone, split into one IG per zone (see the multi-zone error)","Re-run 'kops update cluster' and confirm the InstanceGroupManager task is generated"],"exampleFix":"// before\nmetadata:\n  name: control-plane\nspec:\n  role: ControlPlane\n  zones: []\n// after\nspec:\n  role: ControlPlane\n  zones: [us-central1-a]","handlingStrategy":"validation","validationCode":"for _, ig := range instanceGroups {\n\tif ig.RunsAPIServer() && len(ig.Spec.Zones) != 1 {\n\t\treturn fmt.Errorf(\"IG %q must specify exactly one zone for GCP internal LB\", ig.Name)\n\t}\n}","typeGuard":"func hasExactlyOneZone(ig *kops.InstanceGroup) bool {\n\treturn ig.RunsAPIServer() && len(ig.Spec.Zones) == 1\n}","tryCatchPattern":null,"preventionTips":["Always populate spec.zones on GCP instance groups that serve the API","Validate IG manifests against cluster zones before update","Generate IGs with kOps CLI rather than hand-written manifests","Include zone checks in CI for cluster manifest repos"],"tags":["kops","gcp","zones","instance-group"],"backgroundTag":"missing-instance-group-zone","analyzedSha":"4c8573c808a73d578c5eadc86d410646ea0b0d73","analyzedAt":"2026-09-05T04:13:19.212Z","contentChangedAt":"2026-09-05T04:13:19.212Z","schemaVersion":2},"datasetVersion":"2026-09-12T07:17:12.445Z"}