grpc/grpc-java · error · ResourceInvalidException

HttpConnectionManager contains invalid RDS: missing…

Error message

HttpConnectionManager contains invalid RDS: missing config_source

What it means

An HttpConnectionManager configured with RDS (route discovery service) must supply a config_source telling gRPC where to discover the RouteConfiguration. When the Rds message has no config_source set at all, xDS resource parsing fails with ResourceInvalidException and the listener is rejected.

Solutions

  1. Add a config_source to the Rds block, e.g. ads: {} for ADS-based discovery
  2. Alternatively use config_source { self: {} } for the same management server
  3. If routes are static, inline a route_config in the HttpConnectionManager instead of using RDS

Example fix

// before
rds: { route_config_name: "routes" }
// after
rds: {
  route_config_name: "routes"
  config_source: { ads: {} }
}
Defensive patterns

Strategy: validation

Validate before calling

// Java (proto): check RDS completeness before applying
if (hcm.hasRds() && !hcm.getRds().hasConfigSource()) {
  throw new IllegalArgumentException("rds requires config_source (e.g. ads: {})");
}

Try / catch

try {
  xdsClient.watchResource(LISTENER, name, listenerWatcher);
} catch (ResourceInvalidException e) {
  if (e.getMessage().contains("missing config_source")) {
    log.error("RDS block lacks config_source; fix control plane template");
  }
}

Prevention

When it happens

Trigger: parseHttpConnectionManager sees proto.hasRds() true but rds.hasConfigSource() false — i.e. an Rds block with only a route_config_name and no config_source field.

Common situations: Envoy listener config omitting config_source under rds; YAML-to-proto conversion dropping the nested field; hand-crafted RDS blocks copied from examples that used ADS implicitly in Envoy but must be explicit here.

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/c79d987df9e7e1c7. Report an issue: GitHub.

Appendix: source

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

      }
      if ((i < proto.getHttpFiltersCount() - 1) && isTerminalFilter(filterConfig.getStruct())) {
        throw new ResourceInvalidException("A terminal HttpFilter must be the last filter: "
            + filterName);
      }
      filterConfigs.add(new Filter.NamedFilterConfig(filterName, filterConfig.getStruct()));
    }

    // Parse inlined RouteConfiguration or RDS.
    if (proto.hasRouteConfig()) {
      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);
  }

View on GitHub (pinned to 64daddc1f3)