{"record":{"id":"90c80c578a05f6ae","repo":"grpc/grpc-java","slug":"cluster-cluster-getname-unspecified-clu","errorCode":null,"errorMessage":"Cluster \" + cluster.getName() + \": unspecified cluster discovery type","messagePattern":"Cluster \" \\+ cluster\\.getName\\(\\) \\+ \": unspecified cluster discovery type","errorType":"validation","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/XdsClusterResource.java","lineNumber":156,"sourceCode":"\n  @VisibleForTesting\n  static CdsUpdate processCluster(Cluster cluster,\n                                  Set<String> certProviderInstances,\n                                  ServerInfo serverInfo,\n                                  LoadBalancerRegistry loadBalancerRegistry)\n      throws ResourceInvalidException {\n    StructOrError<CdsUpdate.Builder> structOrError;\n    switch (cluster.getClusterDiscoveryTypeCase()) {\n      case TYPE:\n        structOrError = parseNonAggregateCluster(cluster,\n            certProviderInstances, serverInfo);\n        break;\n      case CLUSTER_TYPE:\n        structOrError = parseAggregateCluster(cluster);\n        break;\n      case CLUSTERDISCOVERYTYPE_NOT_SET:\n      default:\n        throw new ResourceInvalidException(\n            \"Cluster \" + cluster.getName() + \": unspecified cluster discovery type\");\n    }\n    if (structOrError.getErrorDetail() != null) {\n      throw new ResourceInvalidException(structOrError.getErrorDetail());\n    }\n    CdsUpdate.Builder updateBuilder = structOrError.getStruct();\n\n    ImmutableMap<String, ?> lbPolicyConfig = LoadBalancerConfigFactory.newConfig(cluster,\n        enableLeastRequest);\n\n    NameResolver.ConfigOrError configOrError\n        = GracefulSwitchLoadBalancer.parseLoadBalancingPolicyConfig(\n            ImmutableList.of(lbPolicyConfig), loadBalancerRegistry);\n    if (configOrError.getError() != null) {\n      throw new ResourceInvalidException(\n          \"Failed to parse lb config for cluster '\" + cluster.getName() + \"': \"\n          + configOrError.getError());\n    }","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/XdsClusterResource.java#L138-L174","documentation":"When parsing a Cluster proto, processCluster switches on the cluster_type oneof. If the discovery type is CLUSTERDISCOVERYTYPE_NOT_SET (or an unrecognized value), the cluster does not declare how it is discovered (STATIC, STRICT_DNS, EDS, LOGICAL_DNS, or AGGREGATE), so parsing throws ResourceInvalidException.","triggerScenarios":"The xDS server sends a Cluster message with neither server_discovery_type, cluster_type, nor the EDS fields populated, i.e. the oneof is unset.","commonSituations":"Control-plane bugs emitting empty cluster protos; hand-crafted test fixtures missing cluster_type; proto serialization dropping default-valued fields when the server builds the Cluster incorrectly.","solutions":["Set a valid discovery type on the cluster config at the management server (e.g. EDS with eds_cluster_config, or STATIC with load_assignment)","Update the xDS control plane so emitted clusters always populate the cluster_type oneof","Add validation on the server before publishing CDS resources"],"exampleFix":"// before\nCluster.newBuilder().setName(\"cluster1\").build()\n// after\nCluster.newBuilder().setName(\"cluster1\")\n    .setType(Cluster.DiscoveryType.EDS)\n    .setEdsClusterConfig(Cluster.EdsClusterConfig.newBuilder().setEdsServiceName(\"cluster1\"))\n    .build()","handlingStrategy":"validation","validationCode":"if (cluster.getClusterTypeCase() == Cluster.ClusterTypeCase.CLUSTERDISCOVERYTYPE_NOT_SET) {\n  throw new ResourceInvalidException(\"Cluster \" + cluster.getName() + \" has no discovery type\");\n}","typeGuard":"boolean hasDiscoveryType(Cluster c) {\n  return c.getClusterTypeCase() != Cluster.ClusterTypeCase.CLUSTERDISCOVERYTYPE_NOT_SET;\n}","tryCatchPattern":"try {\n  cdsUpdate = xdsClusterResource.parseResource(args);\n} catch (ResourceInvalidException e) {\n  logger.atWarning().log(\"Cluster rejected: %s\", e.getMessage());\n  return Status.INVALID_ARGUMENT.withDescription(e.getMessage()).asException();\n}","preventionTips":["Always set type (or cluster_type for aggregates) on cluster configs","Validate Cluster protos on the control plane before publishing","Cover emitted clusters with schema checks in CI"],"tags":["grpc","xds","cds","config-validation"],"backgroundTag":"invalid-enum-value","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}