{"record":{"id":"0d1811f32c88b7f7","repo":"grpc/grpc-go","slug":"received-cluster-resource-that-contains-invalid-se","errorCode":null,"errorMessage":"received Cluster resource that contains invalid security config: %v","messagePattern":"received Cluster resource that contains invalid security config: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/balancer/clusterimpl/clusterimpl.go","lineNumber":434,"sourceCode":"\t\tc := xdsclient.FromResolverState(s.ResolverState)\n\t\tif c == nil {\n\t\t\treturn balancer.ErrBadResolverState\n\t\t}\n\t\tb.xdsClient = c\n\t}\n\n\txdsConfig := xdsresource.XDSConfigFromResolverState(s.ResolverState)\n\tif xdsConfig == nil {\n\t\tb.logger.Warningf(\"Received balancer config with no xDS config\")\n\t\treturn balancer.ErrBadResolverState\n\t}\n\tclusterCfg := xdsConfig.Clusters[newConfig.Cluster]\n\tclusterUpdate := clusterCfg.Config.Cluster\n\tif err := b.handleSecurityConfig(clusterUpdate.SecurityCfg); err != nil {\n\t\t// If the security config is invalid, for example, if the provider\n\t\t// instance is not found in the bootstrap config, we need to put the\n\t\t// channel in transient failure.\n\t\treturn fmt.Errorf(\"received Cluster resource that contains invalid security config: %v\", err)\n\n\t}\n\t// Update load reporting config. This needs to be done before updating the\n\t// child policy because we need the loadStore from the updated client to be\n\t// passed to the ccWrapper, so that the next picker from the child policy\n\t// will pick up the new loadStore.\n\tif err := b.updateLoadStore(clusterUpdate); err != nil {\n\t\treturn err\n\t}\n\n\t// Build config for the gracefulswitch balancer. It is safe to ignore JSON\n\t// marshaling errors here, since the config was already validated as part of\n\t// ParseConfig().\n\tcfg := []map[string]any{{newConfig.ChildPolicy.Name: newConfig.ChildPolicy.Config}}\n\tcfgJSON, _ := json.Marshal(cfg)\n\tparsedCfg, err := gracefulswitch.ParseConfig(cfgJSON)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/grpc/grpc-go/blob/03255a9237b6eb32710f6bc4f2de9a675b99fe36/internal/xds/balancer/clusterimpl/clusterimpl.go#L416-L452","documentation":"The cluster_impl balancer processes the security configuration from the cluster resource by creating certificate provider plugins and building HandshakeInfo. This error wraps any failure from handleSecurityConfig, which includes building identity/root cert providers, setting up SAN matchers, and configuring SNI. The security config controls mTLS and certificate validation for the cluster's connections.","triggerScenarios":"Triggered in cluster_impl's UpdateClientConnState when handleSecurityConfig(clusterUpdate.SecurityCfg) returns an error. The security config comes from the CDS resource. Failures include: certificate provider build errors (file not found, cert/key mismatch), missing provider instance in bootstrap config, or the security config references a provider instance name not configured in the bootstrap.","commonSituations":"The xDS bootstrap config doesn't have a certificate provider matching the instance name in the cluster's security config; the cluster resource references a fallback security config but xDS credentials are not in use; certificate files are missing or unreadable; the SAN matchers in the security config are malformed; the management server sends a security config that doesn't match any bootstrap provider.","solutions":["Verify the xDS bootstrap config's certificate_providers section contains entries for all instance names referenced by cluster security configs","Check that certificate and key files exist and are readable at the paths in the bootstrap config","Compare the security config's provider instance names with the bootstrap config's provider names — they must match exactly","If not using xDS credentials, ensure the bootstrap or dial options don't enable xdsCredentials unnecessarily","Enable GRPC_GO_LOG_SEVERITY=info to see the wrapped error from handleSecurityConfig for the specific root cause"],"exampleFix":"// before: bootstrap missing the provider referenced by cluster security config\n// cluster security config references \"mtls-identity\" but bootstrap only has \"default\"\n// after: add the missing provider to bootstrap\n{\"certificate_providers\": {\n  \"default\": {...},\n  \"mtls-identity\": {\"plugin_name\": \"file_watcher\", \"config\": {\"certificate_file\": \"/etc/certs/identity.crt\", \"private_key_file\": \"/etc/certs/identity.key\"}}\n}}","handlingStrategy":"validation","validationCode":"// Verify security config providers exist in bootstrap before relying on them\nfunc validateSecurityProviders(bootstrapPath, securityInstanceName string) error {\n    data, err := os.ReadFile(bootstrapPath)\n    if err != nil { return err }\n    var cfg struct {\n        CertProviders map[string]json.RawMessage `json:\"certificate_providers\"`\n    }\n    json.Unmarshal(data, &cfg)\n    if _, ok := cfg.CertProviders[securityInstanceName]; !ok {\n        return fmt.Errorf(\"security provider %q not found in bootstrap config\", securityInstanceName)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// Channel enters TRANSIENT_FAILURE for the affected cluster\nif conn.GetState() == connectivity.TransientFailure {\n    // check logs for 'invalid security config'\n    // verify bootstrap providers match cluster security config\n}","preventionTips":["Ensure bootstrap config contains certificate providers for all instance names referenced by cluster security configs","Validate certificate files exist and match (cert/key pair)","Test security configuration in staging with same file paths as production","Cross-reference management server security config instance names with bootstrap config keys"],"tags":["xds","clusterimpl","security","mtls","certificate","bootstrap","transient-failure"],"analyzedSha":"03255a9237b6eb32710f6bc4f2de9a675b99fe36","analyzedAt":"2026-08-07T00:29:34.215Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}