grpc/grpc-java · error · ResourceInvalidException
Unsupported ClusterSpecifierPlugin type
Error message
Unsupported ClusterSpecifierPlugin type: ${typeUrl} What it means
The ClusterSpecifierPlugin's type_url does not correspond to any plugin implementation registered in the ClusterSpecifierPlugin registry. Unless the plugin is marked is_optional, the RouteConfiguration is rejected because gRPC cannot interpret the plugin semantics.
Solutions
- Upgrade grpc-xds to a version that supports the plugin type referenced by the type_url
- Change the route config to use a supported cluster specifier (plain cluster or weighted clusters)
- If the plugin is genuinely optional, set is_optional: true on the ClusterSpecifierPlugin so it's skipped
- Fix a typo'd or wrong type_url in the plugin extension config
Example fix
// before
cluster_specifier_plugins: [{
extension: {name: "p", typed_config: {"@type": "type.googleapis.com/unknown.Plugin"}}
}]
// after
cluster_specifier_plugins: [{
extension: {name: "p", typed_config: {"@type": "type.googleapis.com/xds.type.matcher.v3.Matcher", ...}},
is_optional: true
}] Defensive patterns
Strategy: fallback
Validate before calling
// Check plugin type support before deploying the route config
String typeUrl = extractTypeUrl(plugin.getTypedConfig());
if (!SUPPORTED_PLUGIN_TYPE_URLS.contains(typeUrl) && !plugin.getIsOptional()) {
throw new IllegalArgumentException("Unsupported plugin type: " + typeUrl);
} Try / catch
try {
xdsClient.watchResource(ROUTE_CONFIGURATION, name, watcher);
} catch (ResourceInvalidException e) {
if (e.getMessage().startsWith("Unsupported ClusterSpecifierPlugin type")) {
log.warn("Falling back to non-plugin routing");
}
} Prevention
- Upgrade grpc-xds when the control plane emits newer plugin types
- Mark non-critical plugins is_optional so unsupported types are skipped
- Keep an allowlist of plugin type_urls supported by your gRPC version
When it happens
Trigger: parseClusterSpecifierPlugin: registry.get(typeUrl) returns null (unknown type_url in the plugin's extension config) and pluginProto.getIsOptional() is false.
Common situations: Configs authored for newer/other Envoy plugin types (e.g. matcher-based plugins not yet supported by the gRPC version); version skew between control plane and grpc-xds; typo'd type_url in hand-written configs.
Related errors
- HttpConnectionManager with original_ip_detection_extensions…
- HttpConnectionManager with xff_num_trusted_hops unsupported
- Listener cannot have listener_filters
- Listener cannot have use_original_dst set to true
- A terminal HttpFilter must be the last filter
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/116711898bd983fc.
Report an issue: GitHub.
Appendix: source
Thrown at xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java:632
String pluginName = extension.getName();
Any anyConfig = extension.getTypedConfig();
String typeUrl = anyConfig.getTypeUrl();
Message rawConfig = anyConfig;
if (typeUrl.equals(TYPE_URL_TYPED_STRUCT_UDPA) || typeUrl.equals(TYPE_URL_TYPED_STRUCT)) {
try {
TypedStruct typedStruct = unpackCompatibleType(
anyConfig, TypedStruct.class, TYPE_URL_TYPED_STRUCT_UDPA, TYPE_URL_TYPED_STRUCT);
typeUrl = typedStruct.getTypeUrl();
rawConfig = typedStruct.getValue();
} catch (InvalidProtocolBufferException e) {
throw new ResourceInvalidException(
"ClusterSpecifierPlugin [" + pluginName + "] contains invalid proto", e);
}
}
io.grpc.xds.ClusterSpecifierPlugin plugin = registry.get(typeUrl);
if (plugin == null) {
if (!pluginProto.getIsOptional()) {
throw new ResourceInvalidException("Unsupported ClusterSpecifierPlugin type: " + typeUrl);
}
return null;
}
ConfigOrError<? extends PluginConfig> pluginConfigOrError = plugin.parsePlugin(rawConfig);
if (pluginConfigOrError.errorDetail != null) {
throw new ResourceInvalidException(pluginConfigOrError.errorDetail);
}
return pluginConfigOrError.config;
}
static final class RdsUpdate implements ResourceUpdate {
// The list virtual hosts that make up the route table.
final List<VirtualHost> virtualHosts;
RdsUpdate(List<VirtualHost> virtualHosts) {
this.virtualHosts = Collections.unmodifiableList(
new ArrayList<>(checkNotNull(virtualHosts, "virtualHosts")));
}View on GitHub (pinned to 64daddc1f3)