{"record":{"id":"fe238916a27f33bf","repo":"grpc/grpc-java","slug":"routeconfiguration-contains-invalid-virtual-host","errorCode":null,"errorMessage":"RouteConfiguration contains invalid virtual host: ${virtualHost.getErrorDetail()}","messagePattern":"RouteConfiguration contains invalid virtual host: (.+?)","errorType":"exception","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java","lineNumber":173,"sourceCode":"        if (pluginConfig != null) {\n          if (pluginConfigMap.put(pluginName, pluginConfig) != null) {\n            throw new ResourceInvalidException(\n                \"Multiple ClusterSpecifierPlugins with the same name: \" + pluginName);\n          }\n        } else {\n          // The plugin parsed successfully, and it's not supported, but it's marked as optional.\n          optionalPlugins.add(pluginName);\n        }\n      }\n    }\n    List<VirtualHost> virtualHosts = new ArrayList<>(routeConfig.getVirtualHostsCount());\n    for (io.envoyproxy.envoy.config.route.v3.VirtualHost virtualHostProto\n        : routeConfig.getVirtualHostsList()) {\n      StructOrError<VirtualHost> virtualHost =\n          parseVirtualHost(virtualHostProto, filterRegistry, pluginConfigMap,\n              optionalPlugins.build(), args);\n      if (virtualHost.getErrorDetail() != null) {\n        throw new ResourceInvalidException(\n            \"RouteConfiguration contains invalid virtual host: \" + virtualHost.getErrorDetail());\n      }\n      virtualHosts.add(virtualHost.getStruct());\n    }\n    return virtualHosts;\n  }\n\n  private static StructOrError<VirtualHost> parseVirtualHost(\n      io.envoyproxy.envoy.config.route.v3.VirtualHost proto, FilterRegistry filterRegistry,\n       Map<String, PluginConfig> pluginConfigMap,\n      Set<String> optionalPlugins, XdsResourceType.Args args) {\n    String name = proto.getName();\n    List<Route> routes = new ArrayList<>(proto.getRoutesCount());\n    for (io.envoyproxy.envoy.config.route.v3.Route routeProto : proto.getRoutesList()) {\n      StructOrError<Route> route = parseRoute(\n          routeProto, filterRegistry, pluginConfigMap, optionalPlugins, args);\n      if (route == null) {\n        continue;","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java#L155-L191","documentation":"One of the RouteConfiguration's virtual hosts failed validation: parseVirtualHost returned a StructOrError carrying an errorDetail (e.g. invalid domains, bad route match, or unsupported route action). The whole RouteConfiguration is rejected because every virtual host must be valid.","triggerScenarios":"extractVirtualHosts parsing routeConfig.getVirtualHostsList(); parseVirtualHost returns non-null errorDetail — e.g. a vhost with empty/overlapping domains, routes with no matching action, or invalid cluster_specifier_plugin references.","commonSituations":"Route configs from Envoy using features gRPC xDS doesn't support (redirect, direct_response nuances, weighted clusters); duplicate/invalid domains in vhosts; routes referencing nonexistent plugin names.","solutions":["Read the embedded errorDetail in the message — it names the exact vhost validation failure","Fix the offending virtual host (domains, routes, or action) per the detail","Remove or simplify routes using unsupported Envoy features","Validate the RouteConfiguration against gRPC xDS-supported route semantics before deployment"],"exampleFix":"// before\nvirtual_hosts: [{name: \"a\", domains: [\"\"], routes: [{}]}] // empty route action\n// after\nvirtual_hosts: [{\n  name: \"a\",\n  domains: [\"example.com\"],\n  routes: [{match: {prefix: \"/\"}, route: {cluster: \"service\"}}]\n}]","handlingStrategy":"validation","validationCode":"// Pre-validate each virtual host minimally\nfor (VirtualHostProto vh : rc.getVirtualHostsList()) {\n  if (vh.getDomainsList().isEmpty() || vh.getRoutesList().isEmpty()) {\n    throw new IllegalArgumentException(\"vhost \" + vh.getName() + \" missing domains/routes\");\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  xdsClient.watchResource(ROUTE_CONFIGURATION, name, watcher);\n} catch (ResourceInvalidException e) {\n  // message embeds the per-vhost errorDetail\n  log.error(\"Invalid vhost: {}\", e.getMessage());\n}","preventionTips":["Read the embedded errorDetail — it pinpoints the failing vhost and reason","Restrict routes to gRPC-supported actions (route/cluster, weighted clusters)","Test route configs against gRPC xDS before Envoy-wide rollout"],"tags":["xds","grpc","route-configuration","virtual-host"],"backgroundTag":"schema-validation-failed","analyzedSha":"64daddc1f3d1975670f769f3e97bde8b2ba32d25","analyzedAt":"2026-09-08T06:14:57.704Z","contentChangedAt":"2026-09-08T06:14:57.704Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}