grpc/grpc-java · error · ResourceInvalidException

Failed to parse xDS filter metadata for cluster '" + cluster

Error message

Failed to parse xDS filter metadata for cluster '" + cluster.getName() + "': " + e.getMessage()

What it means

processCluster parses the cluster's xDS filter metadata through the MetadataRegistry. If parsing raises ResourceInvalidException (unknown or malformed filter metadata entries), it is re-thrown with the cluster name and original message attached so the offending CDS resource is identifiable.

Source

Thrown at xds/src/main/java/io/grpc/xds/XdsClusterResource.java:186

        = GracefulSwitchLoadBalancer.parseLoadBalancingPolicyConfig(
            ImmutableList.of(lbPolicyConfig), loadBalancerRegistry);
    if (configOrError.getError() != null) {
      throw new ResourceInvalidException(
          "Failed to parse lb config for cluster '" + cluster.getName() + "': "
          + configOrError.getError());
    }

    updateBuilder.lbPolicyConfig(configOrError.getConfig(), lbPolicyConfig);
    updateBuilder.filterMetadata(
        ImmutableMap.copyOf(cluster.getMetadata().getFilterMetadataMap()));

    try {
      MetadataRegistry registry = MetadataRegistry.getInstance();
      ImmutableMap<String, Object> parsedFilterMetadata =
          registry.parseMetadata(cluster.getMetadata());
      updateBuilder.parsedMetadata(parsedFilterMetadata);
    } catch (ResourceInvalidException e) {
      throw new ResourceInvalidException(
          "Failed to parse xDS filter metadata for cluster '" + cluster.getName() + "': "
              + e.getMessage(), e);
    }

    return updateBuilder.build();
  }

  private static StructOrError<CdsUpdate.Builder> parseAggregateCluster(Cluster cluster) {
    String clusterName = cluster.getName();
    Cluster.CustomClusterType customType = cluster.getClusterType();
    String typeName = customType.getName();
    if (!typeName.equals(AGGREGATE_CLUSTER_TYPE_NAME)) {
      return StructOrError.fromError(
          "Cluster " + clusterName + ": unsupported custom cluster type: " + typeName);
    }
    io.envoyproxy.envoy.extensions.clusters.aggregate.v3.ClusterConfig clusterConfig;
    try {
      clusterConfig = unpackCompatibleType(customType.getTypedConfig(),

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Remove or correct unsupported filter metadata entries from the cluster's metadata on the management server
  2. Only attach filter metadata that gRPC's MetadataRegistry understands for the cluster
  3. Upgrade grpc-java so the registry recognizes the newer filter metadata types

Example fix

// before
metadata: {filter_metadata: {envoy.filters.http.unknown_filter: {foo: 1}}}
// after
metadata: {filter_metadata: {envoy.filters.http.rbac: {rules: <valid RBAC struct>}}}
Defensive patterns

Strategy: try-catch

Validate before calling

try {
  MetadataRegistry.getInstance().parseMetadata(cluster.getMetadata());
} catch (ResourceInvalidException e) {
  // fix or strip metadata before publishing
}

Try / catch

try {
  cdsUpdate = xdsClusterResource.parseResource(args);
} catch (ResourceInvalidException e) {
  if (e.getMessage().contains("filter metadata")) {
    logger.atWarning().log("Cluster %s has unsupported metadata", clusterName);
  }
}

Prevention

When it happens

Trigger: A Cluster's metadata map contains filter metadata keys/values that MetadataRegistry.parseMetadata cannot interpret — e.g. malformed envoy.filters.http.* structs or unknown filter names.

Common situations: Clusters carrying Envoy HTTP filter metadata not relevant/known to gRPC; management server emitting metadata with wrong value types (struct vs list); newly introduced filters sent to older clients.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/4925b75f08cd6e98. Report an issue: GitHub.