{"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/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/balancer/clusterimpl/clusterimpl.go#L416-L452","documentation":"UpdateClientConnState calls handleSecurityConfig to materialize certificate providers for the Cluster resource's SecurityCfg (clusterimpl.go:430-436). If a referenced provider instance is not declared in the bootstrap configuration's certificate_providers map, buildProvider/buildProviders fails and the error is wrapped here. The whole update is rejected rather than silently falling back to insecure credentials.","triggerScenarios":"clusterUpdate.SecurityCfg.RootInstanceName or IdentityInstanceName is not present in bootstrap.CertificateProviderConfigs(); buildProviderFunc returns the \"xds: failed to get security plugin instance\" error because cfg.Build() cannot find the named provider.","commonSituations":"Bootstrap file generated without the cert provider instance the control plane references; new security config deployed on the management server without updating client bootstrap; mismatched instance names between bootstrap and Cluster resource; certificate provider plugin not registered.","solutions":["Add the missing certificate provider instance to the bootstrap file's certificate_providers map with matching plugin_name.","Verify RootInstanceName/IdentityInstanceName/RootCertName/IdentityCertName in the xDS Cluster resource match the bootstrap keys exactly.","Regenerate the bootstrap file using the same tooling/config as the control plane deployment."],"exampleFix":"// before (bootstrap.json)\n{\n  \"xds_servers\": [...],\n  \"certificate_providers\": {}\n}\n// after\n{\n  \"xds_servers\": [...],\n  \"certificate_providers\": {\n    \"default\": {\n      \"plugin_name\": \"file_watcher\",\n      \"config\": {\"certificate_file\": \"/etc/cert.pem\", \"private_key_file\": \"/etc/key.pem\", \"ca_file\": \"/etc/ca.pem\", \"refresh_interval\": \"300s\"}\n    }\n  }\n}","handlingStrategy":"validation","validationCode":"// Before dialing, ensure every cert provider instance referenced by the control plane is in the bootstrap.\nfunc validateSecurityConfig(bootstrapCfg *bootstrap.Config, securityCfg *xdsresource.SecurityConfig) error {\n    if securityCfg == nil { return nil }\n    cpc := bootstrapCfg.CertProviderConfigs()\n    for _, name := range []string{securityCfg.RootInstanceName, securityCfg.IdentityInstanceName} {\n        if name == \"\" { continue }\n        if _, ok := cpc[name]; !ok {\n            return fmt.Errorf(\"cert provider instance %q missing from bootstrap\", name)\n        }\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Generate the bootstrap file with the same tooling that manages the control plane security config.","Add a startup self-test that materializes each referenced provider via buildProvider.","Treat security config drift as a deployment blocker, not a runtime warning."],"tags":["go","grpc","xds","security","bootstrap","certificate","clusterimpl"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}