grpc/grpc-java · error · ResourceInvalidException

common-tls-context is required in upstream-tls-context

Error message

common-tls-context is required in upstream-tls-context

What it means

validateUpstreamTlsContext throws this ResourceInvalidException when an upstream_tls_context is present on a Cluster but omits its required common_tls_context sub-message. The common_tls_context carries the TLS transport-protocol config (validation context, certificates, ALPN), and gRPC's xDS implementation cannot build a TLS channel without it, so the Cluster resource is rejected.

Source

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

    return outlierDetection;
  }

  static boolean hasNegativeValues(Duration duration) {
    return duration.getSeconds() < 0 || duration.getNanos() < 0;
  }

  @VisibleForTesting
  static io.envoyproxy.envoy.extensions.transport_sockets.tls.v3.UpstreamTlsContext
      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");

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Add a common_tls_context to upstream_tls_context, at minimum a validation_context with a trusted CA (e.g. combined via combined_validation_context with a CertificateValidationContext from your certificate_providers_instance).
  2. Verify the emitted proto actually sets common_tls_context, not just sibling fields.
  3. Check that YAML/JSON serialization is not dropping empty nested messages.
  4. Confirm the field name/casing matches the proto (common_tls_context in JSON).

Example fix

# before
upstream_tls_context: {}
# after
upstream_tls_context:
  common_tls_context:
    validation_context:
      trusted_ca:
        filename: /etc/certs/ca.pem
Defensive patterns

Strategy: validation

Validate before calling

boolean hasCommonTlsContext(ClusterOuterClass.Cluster cluster) {
  return cluster.hasUpstreamTlsContext()
      && cluster.getUpstreamTlsContext().hasCommonTlsContext();
}

Type guard

boolean hasUpstreamTls(com.envoyproxy.envoy.config.cluster.v3.Cluster c) {
  return c.hasUpstreamTlsContext()
      && c.getUpstreamTlsContext().hasCommonTlsContext();
}

Try / catch

try {
  cluster = parseCluster(raw);
} catch (io.grpc.xds.ResourceInvalidException e) {
  if (e.getMessage().contains("common-tls-context")) {
    log.error("upstream_tls_context missing common_tls_context in CDS resource");
  }
  return null;
}

Prevention

When it happens

Trigger: A Cluster resource parsed by parseNonAggregateCluster includes upstream_tls_context but leaves common_tls_context unset (hasCommonTlsContext() is false), so the else-branch throws.

Common situations: Control planes emitting upstream_tls_context with only extension fields; truncated or hand-trimmed config files; users migrating Envoy configs and dropping the nested block; template engines rendering empty common_tls_context that gets stripped as unset.

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