grpc/grpc-java · error · ResourceInvalidException

HttpConnectionManager neither has inlined route_config nor…

Error message

HttpConnectionManager neither has inlined route_config nor RDS

What it means

An HttpConnectionManager must provide routing information either as an inlined route_config or via an Rds reference. When neither field is present the resource is structurally incomplete, so xDS parsing throws ResourceInvalidException and the listener is discarded as invalid.

Solutions

  1. Add an inline route_config with virtual_hosts to the HttpConnectionManager
  2. Or set rds { route_config_name: ..., config_source: { ads: {} } } to discover routes dynamically
  3. Inspect the management server output to confirm it is populating routing fields

Example fix

// before
http_connection_manager: { http_filters: [...] }
// after
http_connection_manager: {
  rds: { route_config_name: "routes", config_source: { ads: {} } }
  http_filters: [...]
}
Defensive patterns

Strategy: validation

Validate before calling

// Java (proto): HCM must have inlined route_config or rds
if (!hcm.hasRouteConfig() && !hcm.hasRds()) {
  throw new IllegalArgumentException("HttpConnectionManager needs route_config or rds");
}

Try / catch

try {
  xdsClient.watchResource(LISTENER, name, listenerWatcher);
} catch (ResourceInvalidException e) {
  log.error("HCM missing routing config: {}", e.getMessage());
}

Prevention

When it happens

Trigger: parseHttpConnectionManager reaches the fall-through throw: the HttpConnectionManager proto has neither route_config (inlined) nor rds set.

Common situations: Minimal hand-written listener configs that only set http_filters; control planes emitting HCM stubs before filling routing; truncated or partially merged protobuf configs.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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

Appendix: source

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

      List<VirtualHost> virtualHosts = extractVirtualHosts(
          proto.getRouteConfig(), filterRegistry, args);
      return io.grpc.xds.HttpConnectionManager.forVirtualHosts(
          maxStreamDuration, virtualHosts, filterConfigs);
    }
    if (proto.hasRds()) {
      Rds rds = proto.getRds();
      if (!rds.hasConfigSource()) {
        throw new ResourceInvalidException(
            "HttpConnectionManager contains invalid RDS: missing config_source");
      }
      if (!rds.getConfigSource().hasAds() && !rds.getConfigSource().hasSelf()) {
        throw new ResourceInvalidException(
            "HttpConnectionManager contains invalid RDS: must specify ADS or self ConfigSource");
      }
      return io.grpc.xds.HttpConnectionManager.forRdsName(
          maxStreamDuration, rds.getRouteConfigName(), filterConfigs);
    }
    throw new ResourceInvalidException(
        "HttpConnectionManager neither has inlined route_config nor RDS");
  }

  // hard-coded: currently router config is the only terminal filter.
  private static boolean isTerminalFilter(Filter.FilterConfig filterConfig) {
    return RouterFilter.ROUTER_CONFIG.equals(filterConfig);
  }

  @VisibleForTesting
  @Nullable // Returns null if the filter is optional but not supported.
  static StructOrError<Filter.FilterConfig> parseHttpFilter(
      io.envoyproxy.envoy.extensions.filters.network.http_connection_manager.v3.HttpFilter
          httpFilter, FilterRegistry filterRegistry, boolean isForClient,
      XdsResourceType.Args args) {
    String filterName = httpFilter.getName();
    boolean isOptional = httpFilter.getIsOptional();
    if (!httpFilter.hasTypedConfig()) {
      return isOptional ? null : StructOrError.fromError(

View on GitHub (pinned to 64daddc1f3)