grpc/grpc-java · error · ResourceInvalidException

downstream-tls-context with require-sni is not supported

Error message

downstream-tls-context with require-sni is not supported

What it means

gRPC xDS does not support the require_sni (Server Name Indication requirement) flag in downstream TLS contexts. Even if common_tls_context is valid, a DownstreamTlsContext carrying require_sni causes validateDownstreamTlsContext to throw ResourceInvalidException and the filter chain to be rejected.

Solutions

  1. Remove the require_sni field from downstream_tls_context in the LDS resource
  2. Achieve SNI-like selection via filter_chain_match server_names instead of require_sni
  3. Split SNI-specific routing into separate filter chains with distinct filter_chain_match rules

Example fix

# before
downstream_tls_context:
  common_tls_context: {...}
  require_sni: true
# after
downstream_tls_context:
  common_tls_context: {...}
filter_chain_match:
  server_names: ["example.com"]
Defensive patterns

Strategy: validation

Validate before calling

if (tlsCtx.hasRequireSni()) {
  throw new IllegalArgumentException(
      "require_sni is unsupported by gRPC xDS; use filter_chain_match.server_names");
}

Try / catch

try {
  listener = XdsListenerResource.parseServerSideListener(proto, ...);
} catch (ResourceInvalidException e) {
  if (e.getMessage().contains("require-sni is not supported")) {
    logger.warn("Strip require_sni and use filter_chain_match server_names", e);
  }
}

Prevention

When it happens

Trigger: A FilterChain's DownstreamTlsContext has the require_sni field set (hasRequireSni() is true), regardless of value, during server-side listener validation.

Common situations: Envoy configs using SNI-based filter chain selection that enable require_sni on TLS contexts; control planes that copy the same TLS context template to every protocol; multi-tenant gateways relying on SNI routing.

Understand the failure class

Related errors


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

Appendix: source

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

        httpConnectionManager,
        downstreamTlsContext,
        tlsContextManager
    );
  }

  @VisibleForTesting
  static DownstreamTlsContext validateDownstreamTlsContext(
      DownstreamTlsContext downstreamTlsContext, Set<String> certProviderInstances)
      throws ResourceInvalidException {
    if (downstreamTlsContext.hasCommonTlsContext()) {
      validateCommonTlsContext(downstreamTlsContext.getCommonTlsContext(), certProviderInstances,
          true);
    } else {
      throw new ResourceInvalidException(
          "common-tls-context is required in downstream-tls-context");
    }
    if (downstreamTlsContext.hasRequireSni()) {
      throw new ResourceInvalidException(
          "downstream-tls-context with require-sni is not supported");
    }
    DownstreamTlsContext.OcspStaplePolicy ocspStaplePolicy = downstreamTlsContext
        .getOcspStaplePolicy();
    if (ocspStaplePolicy != DownstreamTlsContext.OcspStaplePolicy.UNRECOGNIZED
        && ocspStaplePolicy != DownstreamTlsContext.OcspStaplePolicy.LENIENT_STAPLING) {
      throw new ResourceInvalidException(
          "downstream-tls-context with ocsp_staple_policy value " + ocspStaplePolicy.name()
              + " is not supported");
    }
    return downstreamTlsContext;
  }

  private static void validateFilterChainMatchForUniqueness(
      Set<FilterChainMatch> filterChainMatchSet,
      FilterChainMatch filterChainMatch) throws ResourceInvalidException {
    // Flattens complex FilterChainMatch into a list of simple FilterChainMatch'es.
    List<FilterChainMatch> crossProduct = getCrossProduct(filterChainMatch);

View on GitHub (pinned to 64daddc1f3)