{"record":{"id":"652d249557f6037b","repo":"grpc/grpc-java","slug":"clusterspecifierplugin-pluginname-contains-in","errorCode":null,"errorMessage":"ClusterSpecifierPlugin [${pluginName}] contains invalid proto","messagePattern":"ClusterSpecifierPlugin \\[(.+?)\\] contains invalid proto","errorType":"exception","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java","lineNumber":625,"sourceCode":"\n  @Nullable // null if the plugin is not supported, but it's marked as optional.\n  @VisibleForTesting\n  static PluginConfig parseClusterSpecifierPlugin(\n      ClusterSpecifierPlugin pluginProto, ClusterSpecifierPluginRegistry registry)\n      throws ResourceInvalidException {\n    TypedExtensionConfig extension = pluginProto.getExtension();\n    String pluginName = extension.getName();\n    Any anyConfig = extension.getTypedConfig();\n    String typeUrl = anyConfig.getTypeUrl();\n    Message rawConfig = anyConfig;\n    if (typeUrl.equals(TYPE_URL_TYPED_STRUCT_UDPA) || typeUrl.equals(TYPE_URL_TYPED_STRUCT)) {\n      try {\n        TypedStruct typedStruct = unpackCompatibleType(\n            anyConfig, TypedStruct.class, TYPE_URL_TYPED_STRUCT_UDPA, TYPE_URL_TYPED_STRUCT);\n        typeUrl = typedStruct.getTypeUrl();\n        rawConfig = typedStruct.getValue();\n      } catch (InvalidProtocolBufferException e) {\n        throw new ResourceInvalidException(\n            \"ClusterSpecifierPlugin [\" + pluginName + \"] contains invalid proto\", e);\n      }\n    }\n    io.grpc.xds.ClusterSpecifierPlugin plugin = registry.get(typeUrl);\n    if (plugin == null) {\n      if (!pluginProto.getIsOptional()) {\n        throw new ResourceInvalidException(\"Unsupported ClusterSpecifierPlugin type: \" + typeUrl);\n      }\n      return null;\n    }\n    ConfigOrError<? extends PluginConfig> pluginConfigOrError = plugin.parsePlugin(rawConfig);\n    if (pluginConfigOrError.errorDetail != null) {\n      throw new ResourceInvalidException(pluginConfigOrError.errorDetail);\n    }\n    return pluginConfigOrError.config;\n  }\n\n  static final class RdsUpdate implements ResourceUpdate {","sourceCodeStart":607,"sourceCodeEnd":643,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/XdsRouteConfigureResource.java#L607-L643","documentation":"The ClusterSpecifierPlugin's typed config Any could not be unpacked into a TypedStruct (neither the UDPA nor the standard type_url variant), indicating corrupt or non-Struct proto payload. Parsing aborts with ResourceInvalidException wrapping the InvalidProtocolBufferException.","triggerScenarios":"parseClusterSpecifierPlugin calling unpackCompatibleType(anyConfig, TypedStruct.class, TYPE_URL_TYPED_STRUCT_UDPA, TYPE_URL_TYPED_STRUCT) which throws InvalidProtocolBufferException for the plugin identified by pluginName.","commonSituations":"Control plane serializing malformed Struct values into the plugin's Any; binary payloads where a Struct/TypedStruct is expected; version skew where the producer uses an old UDPA type_url the parser can't decode.","solutions":["Regenerate the plugin config so its Any contains a valid (Typed)Struct payload","Check that the type_url inside the Any matches envoy.config.core.v3.TypedStruct or the UDPA variant","Update the control plane / gRPC xDS versions so serialization and parsing agree"],"exampleFix":"// before\nAny any = Any.pack(BytesValue.of(...)); // not a Struct\n// after\nAny any = Any.pack(TypedStruct.newBuilder()\n    .setTypeUrl(\"type.googleapis.com/xds.type.matcher.v3.Matcher\")\n    .setValue(structValue)\n    .build());","handlingStrategy":"try-catch","validationCode":"// Verify the plugin Any is a valid TypedStruct before use\ntry {\n  Any.unpackCompatibleType(any, TypedStruct.class,\n      \"type.googleapis.com/xds.type.TypedStructUdpa\",\n      \"type.googleapis.com/xds.type.TypedStruct\");\n} catch (InvalidProtocolBufferException e) {\n  throw new IllegalArgumentException(\"Malformed plugin config\", e);\n}","typeGuard":"static boolean isTypedStruct(Any any) {\n  return any.getTypeUrl().contains(\"TypedStruct\");\n}","tryCatchPattern":"try {\n  xdsClient.watchResource(ROUTE_CONFIGURATION, name, watcher);\n} catch (ResourceInvalidException e) {\n  log.error(\"ClusterSpecifierPlugin proto invalid: {}\", e.getMessage(), e.getCause());\n}","preventionTips":["Serialize plugin configs as Struct/TypedStruct, never raw bytes","Keep the producing and consuming Envoy API versions aligned","Round-trip plugin configs through a parser in CI to catch malformed payloads"],"tags":["xds","grpc","protobuf","unmarshal"],"backgroundTag":"protobuf-unmarshal-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"}