grpc/grpc-java · error · ResourceInvalidException

common-tls-context with custom_handshaker is not supported

Error message

common-tls-context with custom_handshaker is not supported

What it means

gRPC's xDS cluster resource parsing rejects a CommonTlsContext that carries a custom_handshaker because the Java xDS client only implements the standard Envoy TLS handshake path. Custom handshake extensions cannot be mapped to gRPC's transport, so the whole cluster resource is marked invalid. This check runs inside validateCommonTlsContext during UpstreamTlsContext (and downstream) validation.

Source

Thrown at xds/src/main/java/io/grpc/xds/XdsClusterResource.java:452

      validateUpstreamTlsContext(
      io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext upstreamTlsContext,
      Set<String> certProviderInstances)
      throws ResourceInvalidException {
    if (upstreamTlsContext.hasCommonTlsContext()) {
      validateCommonTlsContext(upstreamTlsContext.getCommonTlsContext(), certProviderInstances,
          false);
    } else {
      throw new ResourceInvalidException("common-tls-context is required in upstream-tls-context");
    }
    return upstreamTlsContext;
  }

  @VisibleForTesting
  static void validateCommonTlsContext(
      CommonTlsContext commonTlsContext, Set<String> certProviderInstances, boolean server)
      throws ResourceInvalidException {
    if (commonTlsContext.hasCustomHandshaker()) {
      throw new ResourceInvalidException(
          "common-tls-context with custom_handshaker is not supported");
    }
    if (commonTlsContext.hasTlsParams()) {
      throw new ResourceInvalidException("common-tls-context with tls_params is not supported");
    }
    if (commonTlsContext.hasValidationContextSdsSecretConfig()) {
      throw new ResourceInvalidException(
          "common-tls-context with validation_context_sds_secret_config is not supported");
    }
    String certInstanceName = getIdentityCertInstanceName(commonTlsContext);
    if (certInstanceName == null) {
      if (server) {
        throw new ResourceInvalidException(
            "tls_certificate_provider_instance is required in downstream-tls-context");
      }
      if (commonTlsContext.getTlsCertificatesCount() > 0) {
        throw new ResourceInvalidException(
            "tls_certificate_provider_instance is unset");

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Remove the custom_handshaker field from common_tls_context in the xDS resource so gRPC uses the standard TLS handshake.
  2. If a custom handshake is required, use Envoy as the data plane instead of gRPC's xDS client, or terminate TLS at a proxy sidecar.
  3. Ensure the control plane filters/omits unsupported fields when generating resources for gRPC clients (per gRFC A-53 style unsupported-field handling).

Example fix

// before (cluster common_tls_context)
"common_tls_context": { "custom_handshaker": { "name": "envoy.tls.handshaker.custom" } }
// after
"common_tls_context": { "tls_params": null, "validation_context": { "trusted_ca": { ... } } }
Defensive patterns

Strategy: validation

Validate before calling

// Java: inspect proto before submitting resource
if (commonTlsContext.hasCustomHandshaker()) {
  throw new IllegalArgumentException("custom_handshaker unsupported by grpc-xds");
}

Try / catch

try {
  clusterAccepted = xdsClient.watchClusterResource(name, watcher);
} catch (ResourceInvalidException e) {
  logger.warning("Cluster rejected: " + e.getMessage()); // surface control-plane config error
}

Prevention

When it happens

Trigger: An xDS CDS/LDS resource (cluster with upstream_tls_context or listener with downstream_tls_context) whose common_tls_context contains a non-empty custom_handshaker field. Thrown as ResourceInvalidException from validateCommonTlsContext when validateUpstreamTlsContext processes the cluster resource.

Common situations: Control planes (e.g. Envoy-oriented tooling or ISVs) that generate config with custom TLS handshake extensions; reuse of Envoy-optimized configurations that gRPC xDS never supported; copy-paste of production Envoy bootstrap clusters into a gRPC application.

Understand the failure class

Related errors


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