kubernetes/kops · error
instance group %q must specify exactly one zone
Error message
instance group %q must specify exactly one zone
What it means
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.
Source
Thrown at pkg/model/gcemodel/api_loadbalancer.go:174
Lifecycle: b.Lifecycle,
}
c.AddTask(hc)
// Collect ControlPlane and APIServer MIGs separately. The API backend service
// includes both (both serve the kube-apiserver), while the kops-controller and
// etcd backend services only include ControlPlane MIGs.
var apiIGMs []*gcetasks.InstanceGroupManager
var controlPlaneIGMs []*gcetasks.InstanceGroupManager // Currently these contain etcd instances
requireEtcdLB := false
for _, ig := range b.InstanceGroups {
if !ig.RunsAPIServer() {
continue
}
if len(ig.Spec.Zones) > 1 {
return fmt.Errorf("instance group %q has %d zones, which is not yet supported for GCP", ig.GetName(), len(ig.Spec.Zones))
}
if len(ig.Spec.Zones) == 0 {
return fmt.Errorf("instance group %q must specify exactly one zone", ig.GetName())
}
zone := ig.Spec.Zones[0]
igm := &gcetasks.InstanceGroupManager{Name: s(gce.NameForInstanceGroupManager(b.Cluster.ObjectMeta.Name, ig.ObjectMeta.Name, zone)), Zone: s(zone)}
apiIGMs = append(apiIGMs, igm)
if ig.IsControlPlane() {
controlPlaneIGMs = append(controlPlaneIGMs, igm)
} else if ig.IsAPIServerOnly() {
requireEtcdLB = b.Cluster.UsesNoneDNS()
} else {
return fmt.Errorf("instance group %q neither control-plane nor api-server", ig.GetName())
}
}
backendService := &gcetasks.BackendService{
Name: s(b.NameForBackendService("api")),
Protocol: s("TCP"),
HealthChecks: []*gcetasks.HealthCheck{hc},
Lifecycle: b.Lifecycle,
LoadBalancingScheme: s("INTERNAL"),View on GitHub (pinned to 4c8573c808)
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
Example fix
// before metadata: name: control-plane spec: role: ControlPlane zones: [] // after spec: role: ControlPlane zones: [us-central1-a]
Defensive patterns
Strategy: validation
Validate before calling
for _, ig := range instanceGroups {
if ig.RunsAPIServer() && len(ig.Spec.Zones) != 1 {
return fmt.Errorf("IG %q must specify exactly one zone for GCP internal LB", ig.Name)
}
} Type guard
func hasExactlyOneZone(ig *kops.InstanceGroup) bool {
return ig.RunsAPIServer() && len(ig.Spec.Zones) == 1
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- instance group %q has %d zones, which is not yet supported f
- instance group %q neither control-plane nor api-server
- error recreating Instance %s: %v
- error listing InstanceGroupManagers: %v
- error getting instance group for MIG %q
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/94d3204fa832ad87.
Report an issue: GitHub.