{"record":{"id":"0362d85559679c7a","repo":"grpc/grpc-java","slug":"filterchain-filterchainname-should-contain-exac","errorCode":null,"errorMessage":"FilterChain ${filterChainName} should contain exact one HttpConnectionManager filter","messagePattern":"FilterChain (.+?) should contain exact one HttpConnectionManager filter","errorType":"validation","errorClass":"ResourceInvalidException","httpStatus":null,"severity":"error","filePath":"xds/src/main/java/io/grpc/xds/XdsListenerResource.java","lineNumber":232,"sourceCode":"\n    return EnvoyServerProtoData.Listener.create(proto.getName(), address, filterChains.build(),\n        defaultFilterChain, socketAddress == null ? null : socketAddress.getProtocol());\n  }\n\n  @VisibleForTesting\n  static FilterChain parseFilterChain(\n      io.envoyproxy.envoy.config.listener.v3.FilterChain proto,\n      String filterChainName,\n      TlsContextManager tlsContextManager,\n      FilterRegistry filterRegistry,\n      // null disables FilterChainMatch uniqueness check, used for defaultFilterChain\n      @Nullable Set<FilterChainMatch> filterChainMatchSet,\n      Set<String> certProviderInstances,\n      XdsResourceType.Args args)\n      throws ResourceInvalidException {\n    // FilterChain contains L4 filters, so we ensure it contains only HCM.\n    if (proto.getFiltersCount() != 1) {\n      throw new ResourceInvalidException(\"FilterChain \" + filterChainName\n          + \" should contain exact one HttpConnectionManager filter\");\n    }\n    io.envoyproxy.envoy.config.listener.v3.Filter l4Filter = proto.getFiltersList().get(0);\n    if (!l4Filter.hasTypedConfig()) {\n      throw new ResourceInvalidException(\n          \"FilterChain \" + filterChainName + \" contains filter \" + l4Filter.getName()\n              + \" without typed_config\");\n    }\n    Any any = l4Filter.getTypedConfig();\n    if (!any.getTypeUrl().equals(TYPE_URL_HTTP_CONNECTION_MANAGER)) {\n      throw new ResourceInvalidException(\n          \"FilterChain \" + filterChainName + \" contains filter \" + l4Filter.getName()\n              + \" with unsupported typed_config type \" + any.getTypeUrl());\n    }\n\n    // Parse HCM.\n    HttpConnectionManager hcmProto;\n    try {","sourceCodeStart":214,"sourceCodeEnd":250,"githubUrl":"https://github.com/grpc/grpc-java/blob/64daddc1f3d1975670f769f3e97bde8b2ba32d25/xds/src/main/java/io/grpc/xds/XdsListenerResource.java#L214-L250","documentation":"A server-side FilterChain must contain exactly one L4 filter, and that filter must be an HttpConnectionManager (HCM) typed config - gRPC xDS does not support arbitrary L4 filter stacks. When filters_count != 1, parseFilterChain throws ResourceInvalidException. This enforces the gRPC xDS server-side protocol contract.","triggerScenarios":"A FilterChain proto has zero filters, or more than one entry in its filters list, when parsed by parseFilterChain (reached from parseServerSideListener).","commonSituations":"Envoy configs copied verbatim that stack multiple filters (e.g. TLS inspector + HCM) inside one filter chain; control planes emitting empty filters lists; mis-generated protos omitting the HCM filter.","solutions":["Ensure each filter_chain contains exactly one filter whose typed_config is envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager","Remove extra filters from the filter chain and move them elsewhere if your control plane supports it","Regenerate the LDS resource so the filters list is populated with a single HCM filter"],"exampleFix":"# before\nfilters: []\n# after\nfilters:\n- name: envoy.filters.network.http_connection_manager\n  typed_config:\n    '@type': type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager","handlingStrategy":"validation","validationCode":"for (FilterChain fc : listener.getFilterChainsList()) {\n  if (fc.getFiltersCount() != 1) {\n    throw new IllegalArgumentException(\n        \"FilterChain must contain exactly one filter, got \" + fc.getFiltersCount());\n  }\n}","typeGuard":null,"tryCatchPattern":"try {\n  listener = XdsListenerResource.parseServerSideListener(proto, ...);\n} catch (ResourceInvalidException e) {\n  if (e.getMessage().contains(\"should contain exact one HttpConnectionManager\")) {\n    logger.warn(\"LDS resource has malformed filters list\", e);\n  }\n}","preventionTips":["Model server-side filter chains as exactly one HCM filter in control-plane templates","Validate LDS resources against the gRPC xDS schema before publishing","Do not port multi-filter Envoy L4 stacks to gRPC xDS consumers"],"tags":["xds","grpc","filter-chain","config-validation"],"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-14T05:17:10.506Z"}