{"record":{"id":"dd6061c872a588ee","repo":"grpc/grpc-go","slug":"xds-config-parsing-for-certificate-provider-plugi","errorCode":null,"errorMessage":"xds: config parsing for certificate provider plugin %q failed during bootstrap: %v","messagePattern":"xds: config parsing for certificate provider plugin %q failed during bootstrap: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/bootstrap/bootstrap.go","lineNumber":620,"sourceCode":"\tc.cpcs = config.CertificateProviders\n\tc.serverListenerResourceNameTemplate = config.ServerListenerResourceNameTemplate\n\tc.clientDefaultListenerResourceNameTemplate = config.ClientDefaultListenerResourceNameTemplate\n\tc.authorities = config.Authorities\n\tc.node = config.Node\n\n\t// Build the certificate providers configuration to ensure that it is valid.\n\tcpcCfgs := make(map[string]*certprovider.BuildableConfig)\n\tgetBuilder := internal.GetCertificateProviderBuilder.(func(string) certprovider.Builder)\n\tfor instance, nameAndConfig := range c.cpcs {\n\t\tname := nameAndConfig.PluginName\n\t\tparser := getBuilder(nameAndConfig.PluginName)\n\t\tif parser == nil {\n\t\t\t// We ignore plugins that we do not know about.\n\t\t\tcontinue\n\t\t}\n\t\tbc, err := parser.ParseConfig(nameAndConfig.Config)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"xds: config parsing for certificate provider plugin %q failed during bootstrap: %v\", name, err)\n\t\t}\n\t\tcpcCfgs[instance] = bc\n\t}\n\tc.certProviderConfigs = cpcCfgs\n\n\t// Default value of the default client listener name template is \"%s\".\n\tif c.clientDefaultListenerResourceNameTemplate == \"\" {\n\t\tc.clientDefaultListenerResourceNameTemplate = \"%s\"\n\t}\n\tif len(c.xDSServers) == 0 {\n\t\treturn fmt.Errorf(\"xds: required field `xds_servers` not found in bootstrap configuration: %s\", string(data))\n\t}\n\n\t// Post-process the authorities' client listener resource template field:\n\t// - if set, it must start with \"xdstp://<authority_name>/\"\n\t// - if not set, it defaults to \"xdstp://<authority_name>/envoy.config.listener.v3.Listener/%s\"\n\tfor name, authority := range c.authorities {\n\t\tprefix := fmt.Sprintf(\"xdstp://%s\", url.PathEscape(name))","sourceCodeStart":602,"sourceCodeEnd":638,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/bootstrap/bootstrap.go#L602-L638","documentation":"Returned by Config.UnmarshalJSON when a certificate provider plugin's ParseConfig fails. Each certificate_providers entry names a plugin and a config blob; if the plugin rejects the config, bootstrap fails with the instance name printed.","triggerScenarios":"Triggered at bootstrap.go:620 when parser.ParseConfig(nameAndConfig.Config) errors. Most commonly the file_watcher (pemfile) plugin rejects a config missing required file fields or with invalid values.","commonSituations":"file_watcher config missing certificate_file/private_key_file when mTLS is required; bad refresh interval; unknown plugin-specific field; mismatched plugin_name spelling.","solutions":["Read the nested %v to see which constraint the plugin rejected.","For file_watcher, supply the required fields: at least one of certificate_file or ca_certificate_file, plus private_key_file when a cert is given, and a refresh_interval.","Verify the plugin_name is spelled exactly (commonly 'file_watcher').","Confirm the cert provider plugin is built into your grpc-go (pemfile is)."],"exampleFix":"// before (missing required file fields)\n\"certificate_providers\":{\"default\":{\"plugin_name\":\"file_watcher\",\"config\":{\"refresh_interval\":\"1s\"}}}\n\n// after\n\"certificate_providers\":{\"default\":{\"plugin_name\":\"file_watcher\",\"config\":{\"certificate_file\":\"/etc/certs/client.crt\",\"private_key_file\":\"/etc/certs/client.key\",\"ca_certificate_file\":\"/etc/certs/ca.crt\",\"refresh_interval\":\"1s\"}}}","handlingStrategy":"validation","validationCode":"// Validate a file_watcher certificate provider config block.\nfunc validateFileWatcher(cfg map[string]any) error {\n    refresh, _ := cfg[\"refresh_interval\"].(string)\n    if refresh == \"\" {\n        return fmt.Errorf(\"file_watcher: refresh_interval required\")\n    }\n    cert, _ := cfg[\"certificate_file\"].(string)\n    ca, _ := cfg[\"ca_certificate_file\"].(string)\n    if cert == \"\" && ca == \"\" {\n        return fmt.Errorf(\"file_watcher: need certificate_file or ca_certificate_file\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := bootstrap.NewConfigFromContents(data); err != nil {\n    if strings.Contains(err.Error(), \"certificate provider plugin\") {\n        // read nested cause, fix the named provider's config.\n    }\n}","preventionTips":["For file_watcher, always set refresh_interval and at least one cert file.","Keep plugin_name spelling exact (file_watcher).","Test the bootstrap in a staging control plane before production."],"tags":["grpc","xds","bootstrap","certificate-provider","file-watcher","config","go"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}