{"record":{"id":"6e75c3baed128fd0","repo":"kubernetes/kops","slug":"unknown-topology-type-q","errorCode":null,"errorMessage":"unknown topology type: %q","messagePattern":"unknown topology type: %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"upup/pkg/fi/cloudup/new_cluster.go","lineNumber":1561,"sourceCode":"\t// Populate the API access, so that it can be discoverable\n\tklog.Infof(\"Cloud Provider ID: %q\", cluster.GetCloudProvider())\n\tif opt.APILoadBalancerType != \"\" || opt.APISSLCertificate != \"\" {\n\t\tcluster.Spec.API.LoadBalancer = &api.LoadBalancerAccessSpec{}\n\t} else {\n\t\tswitch opt.Topology {\n\t\tcase api.TopologyPublic:\n\t\t\tif cluster.UsesNoneDNS() {\n\t\t\t\t// there are no DNS records for the API, so we use a LoadBalancer instead\n\t\t\t\tcluster.Spec.API.LoadBalancer = &api.LoadBalancerAccessSpec{}\n\t\t\t} else {\n\t\t\t\tcluster.Spec.API.DNS = &api.DNSAccessSpec{}\n\t\t\t}\n\n\t\tcase api.TopologyPrivate:\n\t\t\tcluster.Spec.API.LoadBalancer = &api.LoadBalancerAccessSpec{}\n\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown topology type: %q\", opt.Topology)\n\t\t}\n\t}\n\n\tif cluster.Spec.API.LoadBalancer != nil && cluster.Spec.API.LoadBalancer.Type == \"\" {\n\t\tswitch opt.APILoadBalancerType {\n\t\tcase \"\", \"public\":\n\t\t\tcluster.Spec.API.LoadBalancer.Type = api.LoadBalancerTypePublic\n\t\tcase \"internal\":\n\t\t\tcluster.Spec.API.LoadBalancer.Type = api.LoadBalancerTypeInternal\n\t\tdefault:\n\t\t\treturn fmt.Errorf(\"unknown api-loadbalancer-type: %q\", opt.APILoadBalancerType)\n\t\t}\n\t}\n\n\tif cluster.Spec.API.LoadBalancer != nil && opt.APISSLCertificate != \"\" {\n\t\tcluster.Spec.API.LoadBalancer.SSLCertificate = opt.APISSLCertificate\n\t}\n","sourceCodeStart":1543,"sourceCodeEnd":1579,"githubUrl":"https://github.com/kubernetes/kops/blob/4c8573c808a73d578c5eadc86d410646ea0b0d73/upup/pkg/fi/cloudup/new_cluster.go#L1543-L1579","documentation":"setupAPI configures how the Kubernetes API endpoint is exposed and bases decisions on opt.Topology. Its switch only knows public and private; any other topology value reaching here (after the earlier validation) is rejected with this defensive error while creating the cluster.","triggerScenarios":"NewClusterOptions.Topology set to a value other than api.TopologyPublic/api.TopologyPrivate while API access configuration requires topology-specific handling — normally only reachable when constructing options programmatically (Topology field set directly) or when earlier validation is bypassed.","commonSituations":"Go code/tests building NewClusterOptions with an arbitrary Topology string; scripts mutated between validation and use; refactors that removed the setupTopology validation path.","solutions":["Set NewClusterOptions.Topology to \"public\" or \"private\" only.","In Go, use the api.TopologyPublic / api.TopologyPrivate constants.","Ensure the --topology flag value is validated before NewCluster is invoked."],"exampleFix":"// before\nopt := &NewClusterOptions{Topology: \"public,private\"}\n// after\nopt := &NewClusterOptions{Topology: api.TopologyPrivate}","handlingStrategy":"type-guard","validationCode":"if opt.Topology != api.TopologyPublic && opt.Topology != api.TopologyPrivate { return fmt.Errorf(\"topology must be public or private\") }","typeGuard":"func isValidTopology(t string) bool { return t == api.TopologyPublic || t == api.TopologyPrivate }","tryCatchPattern":"if err := NewCluster(ctx, cloud, opt); err != nil && strings.Contains(err.Error(), \"unknown topology type\") { /* fix NewClusterOptions.Topology to a constant and retry */ }","preventionTips":["Always assign topology via api.Topology* constants, not raw strings","Validate opt.Topology before calling NewCluster programmatically","Reuse the same validation as setupTopology in test fixtures"],"tags":["topology","api","cluster-creation","configuration"],"backgroundTag":"invalid-flag-value","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"}