grpc/grpc-go · error

security configuration on the server-side does not contain…

Error message

security configuration on the server-side does not contain root certificate provider instance name, but require_client_cert field is set

What it means

Thrown during server-side filter chain processing: a DownstreamTlsContext set require_client_certificate=true but the resulting SecurityConfig has an empty RootInstanceName. To verify client certs the server needs a root/trust bundle to validate against; requesting client auth without it is contradictory, so grpc-go rejects the chain.

Solutions

  1. Add a validation_context (or combined_validation_context) with a non-empty certificate_provider_instance instance_name for the client root CA.
  2. Alternatively, set require_client_certificate=false if client auth is not actually required.
  3. Confirm the bootstrap certificate_providers defines the root provider name the control plane references for inbound mTLS.

Example fix

// before
//   downstream_tls_context: { require_client_certificate: true, common_tls_context: { tls_certificate_provider_instance: { instance_name: "default" } } }
// after
//   downstream_tls_context: {
//     require_client_certificate: true,
//     common_tls_context: {
//       tls_certificate_provider_instance: { instance_name: "default" },
//       validation_context: { certificate_provider_instance: { instance_name: "client-roots" } }
//     }
//   }
Defensive patterns

Strategy: validation

Validate before calling

// Ensure a server-side downstream TLS context with require_client_cert also has a validation context.
func validateMutualTLS(dtls *envoy_tls_pb.DownstreamTlsContext) error {
    if !dtls.GetRequireClientCertificate().GetValue() { return nil }
    ctc := dtls.GetCommonTlsContext()
    if ctc == nil { return errors.New("require_client_cert set but common_tls_context missing") }
    if ctc.GetValidationContext().GetCertificateProviderInstance().GetInstanceName() == "" &&
       ctc.GetCombinedValidationContext().GetDefaultValidationContext().GetCertificateProviderInstance().GetInstanceName() == "" {
        return errors.New("require_client_cert set but no root certificate provider instance name")
    }
    return nil
}

Try / catch

Catch in LDS watcher; alert ops that mTLS is half-configured. Fix in control plane by adding the root provider or disabling require_client_certificate.

Prevention

When it happens

Trigger: LDS server filter chain sets downstream_tls_context.require_client_certificate=true, but the CommonTlsContext's validation context provides no root certificate provider instance name (and system roots are not configured for that path).

Common situations: Operator enabled mutual TLS (require client cert) but forgot to attach the client CA root provider. Asymmetric SDS setup where identity cert is provisioned but the validation/trust bundle is not. Istio PeerAuthentication set to MUTUAL_TLS without provisioning client root certs for the server.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/cc10603ea274f6a4. Report an issue: GitHub.

Appendix: source

Thrown at internal/xds/xdsclient/xdsresource/unmarshal_lds.go:363

		return emptyFilterChain, fmt.Errorf("failed to unmarshal DownstreamTlsContext in LDS response: %v", err)
	}
	if downstreamCtx.GetRequireSni().GetValue() {
		return emptyFilterChain, fmt.Errorf("require_sni field set to true in DownstreamTlsContext message: %v", downstreamCtx)
	}
	if downstreamCtx.GetOcspStaplePolicy() != v3tlspb.DownstreamTlsContext_LENIENT_STAPLING {
		return emptyFilterChain, fmt.Errorf("ocsp_staple_policy field set to unsupported value in DownstreamTlsContext message: %v", downstreamCtx)
	}
	if downstreamCtx.GetCommonTlsContext() == nil {
		return emptyFilterChain, errors.New("DownstreamTlsContext in LDS response does not contain a CommonTlsContext")
	}
	sc, err := securityConfigFromCommonTLSContext(downstreamCtx.GetCommonTlsContext(), true)
	if err != nil {
		return emptyFilterChain, err
	}
	if sc != nil {
		sc.RequireClientCert = downstreamCtx.GetRequireClientCertificate().GetValue()
		if sc.RequireClientCert && sc.RootInstanceName == "" {
			return emptyFilterChain, errors.New("security configuration on the server-side does not contain root certificate provider instance name, but require_client_cert field is set")
		}
		fcc.SecurityCfg = sc
	}
	return fcc, nil
}

// dstPrefixEntry wraps DestinationPrefixEntry to track build state.
type dstPrefixEntry struct {
	entry         DestinationPrefixEntry
	rawBufferSeen bool
}

func buildFilterChainMap(fcs []*v3listenerpb.FilterChain) (NetworkFilterChainMap, error) {
	dstPrefixEntries := []*dstPrefixEntry{}
	for _, fc := range fcs {
		fcMatch := fc.GetFilterChainMatch()
		if fcMatch.GetDestinationPort().GetValue() != 0 {
			// Destination port is the first match criteria and we do not

View on GitHub (pinned to 0c51461d27)