grpc/grpc-java · error · ResourceInvalidException

Filter chain names must be unique. Found duplicate

Error message

Filter chain names must be unique. Found duplicate: ${filterChainName}

What it means

Each FilterChain in a server-side Listener must have a unique non-empty name so gRPC can identify filter chains in logs and match logic. The parser collects names into a set and throws ResourceInvalidException when a duplicate is added. Resources with duplicate filter chain names are considered invalid and rejected.

Solutions

  1. Give each filter_chain in the Listener a distinct name in the control plane config
  2. Leave the name field empty (the parser auto-generates unique names 'chain_0', 'chain_1', ...) instead of duplicating names
  3. Audit the LDS resource JSON/YAML for repeated filter_chain name values and rename them

Example fix

# before
filter_chains:
- name: fc1
  ...
- name: fc1
  ...
# after
filter_chains:
- name: fc1
  ...
- name: fc2
  ...
Defensive patterns

Strategy: validation

Validate before calling

Set<String> seen = new HashSet<>();
for (FilterChain fc : listener.getFilterChainsList()) {
  if (!seen.add(fc.getName())) {
    throw new IllegalArgumentException("Duplicate filter chain name: " + fc.getName());
  }
}

Try / catch

try {
  listener = XdsListenerResource.parseServerSideListener(proto, ...);
} catch (ResourceInvalidException e) {
  if (e.getMessage().startsWith("Filter chain names must be unique")) {
    logger.warn("Rename duplicated filter chain in LDS resource", e);
  }
}

Prevention

When it happens

Trigger: A Listener proto contains two or more filter_chains entries whose name field is identical (e.g. both set to 'fc1', or both explicitly set to the same string) while processing parseServerSideListener.

Common situations: Copy-pasted filter chain blocks in Envoy-style configs where the name field was left identical; control planes that auto-generate filter chains without unique naming; hand-edited LDS resources.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at xds/src/main/java/io/grpc/xds/XdsListenerResource.java:195

          break;
        default:
          // noop
      }
    }

    ImmutableList.Builder<FilterChain> filterChains = ImmutableList.builder();
    Set<String> filterChainNames = new HashSet<>();
    Set<FilterChainMatch> filterChainMatchSet = new HashSet<>();
    int i = 0;
    for (io.envoyproxy.envoy.config.listener.v3.FilterChain fc : proto.getFilterChainsList()) {
      // May be empty. If it's not empty, required to be unique.
      String filterChainName = fc.getName();
      if (filterChainName.isEmpty()) {
        // Generate a name, so we can identify it in the logs.
        filterChainName = "chain_" + i;
      }
      if (!filterChainNames.add(filterChainName)) {
        throw new ResourceInvalidException("Filter chain names must be unique. "
            + "Found duplicate: " + filterChainName);
      }
      filterChains.add(
          parseFilterChain(fc, filterChainName, tlsContextManager, filterRegistry,
              filterChainMatchSet, certProviderInstances, args));
      i++;
    }

    FilterChain defaultFilterChain = null;
    if (proto.hasDefaultFilterChain()) {
      String defaultFilterChainName = proto.getDefaultFilterChain().getName();
      if (defaultFilterChainName.isEmpty()) {
        defaultFilterChainName = "chain_default";
      }
      defaultFilterChain = parseFilterChain(
          proto.getDefaultFilterChain(), defaultFilterChainName, tlsContextManager, filterRegistry,
          null, certProviderInstances, args);
    }

View on GitHub (pinned to 64daddc1f3)