{"record":{"id":"5197ac2205532d2f","repo":"kubernetes/kops","slug":"must-specify-at-least-one-zone-for-the-cluster-us","errorCode":null,"errorMessage":"must specify at least one zone for the cluster (use --zones)","messagePattern":"must specify at least one zone for the cluster \\(use --zones\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/new_cluster.go","lineNumber":321,"sourceCode":"\t\t\tcluster.Spec.KubeAPIServer.FeatureGates[featureGate] = value\n\t\t\tcluster.Spec.KubeControllerManager.FeatureGates[featureGate] = value\n\t\t\tcluster.Spec.KubeProxy.FeatureGates[featureGate] = value\n\t\t\tcluster.Spec.KubeScheduler.FeatureGates[featureGate] = value\n\t\t}\n\t}\n\n\tif len(opt.AdminAccess) == 0 {\n\t\topt.AdminAccess = []string{\"0.0.0.0/0\", \"::/0\"}\n\t}\n\tcluster.Spec.API.Access = opt.AdminAccess\n\tif len(opt.SSHAccess) != 0 {\n\t\tcluster.Spec.SSHAccess = opt.SSHAccess\n\t} else {\n\t\tcluster.Spec.SSHAccess = opt.AdminAccess\n\t}\n\n\tif len(opt.Zones) == 0 {\n\t\treturn nil, fmt.Errorf(\"must specify at least one zone for the cluster (use --zones)\")\n\t}\n\tallZones := sets.NewString()\n\tallZones.Insert(opt.Zones...)\n\tallZones.Insert(opt.ControlPlaneZones...)\n\n\tif opt.CloudProvider == \"\" {\n\t\tcloud, err := clouds.GuessCloudForPath(cluster.Spec.ConfigStore.Base)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"pass in the cloud provider explicitly using --cloud: %w\", err)\n\t\t}\n\t\tklog.V(2).Infof(\"Inferred %q cloud provider from state store %q\", cloud, cluster.Spec.ConfigStore.Base)\n\t\topt.CloudProvider = string(cloud)\n\t}\n\n\tvar cloud fi.Cloud\n\n\tswitch api.CloudProviderID(opt.CloudProvider) {\n\tcase api.CloudProviderAWS:","sourceCodeStart":303,"sourceCodeEnd":339,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/new_cluster.go#L303-L339","documentation":"NewCluster validation guard: fires when opt.Zones is empty, i.e. kops create cluster was run without --zones. At least one zone is required to derive regions/subnets and place the cluster, so creation is aborted before any cloud calls.","triggerScenarios":"`kops create cluster` without --zones (or with --zones=\"\"), or NewClusterOptions constructed with Zones: nil. Note ControlPlaneZones alone do not satisfy this check — opt.Zones specifically must be non-empty.","commonSituations":"Interactive usage that assumes zones are inferred from the cloud provider; scripts that build flags dynamically and produce an empty --zones; forgetting that even single-zone clusters need an explicit zone.","solutions":["Add --zones, e.g. `kops create cluster --zones us-east-1a,us-east-1b`","Set opt.Zones in NewClusterOptions to at least one zone","Ensure the flag-parsing code actually populates Zones (check for cobra flag name mismatches)"],"exampleFix":"// before\nkops create cluster --name c.example.com --cloud aws\n// after\nkops create cluster --name c.example.com --cloud aws --zones us-east-1a","handlingStrategy":"validation","validationCode":"if len(opt.Zones) == 0 {\n    return fmt.Errorf(\"--zones is required, e.g. --zones us-east-1a\")\n}","typeGuard":"func hasZones(opt *NewClusterOptions) bool {\n    return len(opt.Zones) > 0\n}","tryCatchPattern":null,"preventionTips":["Always pass --zones with create cluster","Remember ControlPlaneZones do not substitute for Zones","Build zone lists from cloud metadata in automation"],"tags":["zones","cli","validation"],"backgroundTag":"missing-required-argument","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"}