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
- 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).
- Verify the emitted proto actually sets common_tls_context, not just sibling fields.
- Check that YAML/JSON serialization is not dropping empty nested messages.
- 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
- Always pair upstream_tls_context with a common_tls_context containing a validation_context/trusted CA.
- Validate with hasCommonTlsContext() on the control plane before publishing.
- Beware templating engines stripping empty nested messages like common_tls_context: {}.
- Test that rendered configs round-trip through the envoy protos without dropping sub-messages.
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.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- downstream-tls-context with ocsp_staple_policy value ${ocspS
- unsupported ExtAuthz service type: only grpc_service is supp
- Invalid ring hash function: " + ringHash.getHashFunction()
- Custom LB config does not contain a JSON object
- Invalid header matcher config: [grpc-] prefixed header name
AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08).
Data as JSON: /api/errors/dd5ada42beba4a4d.
Report an issue: GitHub.