grpc/grpc-go · error

xds: config parsing for certificate provider plugin %q faile

Error message

xds: config parsing for certificate provider plugin %q failed during bootstrap: %v

What it means

During bootstrap unmarshalling the library iterates every entry in certificate_providers, looks up the registered provider builder for the plugin name, and calls ParseConfig on that builder's config block. This error fires when a known provider plugin rejects its own config sub-document. The plugin name and the underlying parse error are both reported.

Source

Thrown at internal/xds/bootstrap/bootstrap.go:620

	c.cpcs = config.CertificateProviders
	c.serverListenerResourceNameTemplate = config.ServerListenerResourceNameTemplate
	c.clientDefaultListenerResourceNameTemplate = config.ClientDefaultListenerResourceNameTemplate
	c.authorities = config.Authorities
	c.node = config.Node

	// Build the certificate providers configuration to ensure that it is valid.
	cpcCfgs := make(map[string]*certprovider.BuildableConfig)
	getBuilder := internal.GetCertificateProviderBuilder.(func(string) certprovider.Builder)
	for instance, nameAndConfig := range c.cpcs {
		name := nameAndConfig.PluginName
		parser := getBuilder(nameAndConfig.PluginName)
		if parser == nil {
			// We ignore plugins that we do not know about.
			continue
		}
		bc, err := parser.ParseConfig(nameAndConfig.Config)
		if err != nil {
			return fmt.Errorf("xds: config parsing for certificate provider plugin %q failed during bootstrap: %v", name, err)
		}
		cpcCfgs[instance] = bc
	}
	c.certProviderConfigs = cpcCfgs

	// Default value of the default client listener name template is "%s".
	if c.clientDefaultListenerResourceNameTemplate == "" {
		c.clientDefaultListenerResourceNameTemplate = "%s"
	}
	if len(c.xDSServers) == 0 {
		return fmt.Errorf("xds: required field `xds_servers` not found in bootstrap configuration: %s", string(data))
	}

	// Post-process the authorities' client listener resource template field:
	// - if set, it must start with "xdstp://<authority_name>/"
	// - if not set, it defaults to "xdstp://<authority_name>/envoy.config.listener.v3.Listener/%s"
	for name, authority := range c.authorities {
		prefix := fmt.Sprintf("xdstp://%s", url.PathEscape(name))

View on GitHub (pinned to 03255a9237)

Solutions

  1. Check the named plugin in the error message and review its required fields against the pemfile (file_watcher) provider schema: at least one of certificate_file or ca_certificate_file must be set.
  2. Ensure every file path in the config block exists and is readable by the process at bootstrap time.
  3. Validate the certificate_providers stanza with the provider's documentation before deploying.
  4. If the plugin is not actually needed, remove the entry rather than leaving a partial config.

Example fix

// before:
//   "certificate_providers": {
//     "default": { "plugin_name": "file_watcher", "config": {} }
//   }
// after:
//   "certificate_providers": {
//     "default": {
//       "plugin_name": "file_watcher",
//       "config": { "certificate_file": "/etc/certs/client.pem",
//                   "private_key_file": "/etc/certs/client.key",
//                   "ca_certificate_file": "/etc/certs/ca.pem" }
//     }
//   }
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate the certificate_providers stanza against known schemas.
func validateCertProviders(raw map[string]json.RawMessage) error {
    for inst, b := range raw {
        var entry struct{ PluginName string `json:"plugin_name"`; Config map[string]any `json:"config"` }
        if err := json.Unmarshal(b, &entry); err != nil {
            return fmt.Errorf("%s: %w", inst, err)
        }
        if entry.PluginName == "file_watcher" {
            if _, ok := entry.Config["certificate_file"]; !ok {
                if _, ok := entry.Config["ca_certificate_file"]; !ok {
                    return fmt.Errorf("%s: file_watcher needs certificate_file or ca_certificate_file", inst)
                }
            }
        }
    }
    return nil
}

Prevention

When it happens

Trigger: A certificate_providers entry references a registered plugin (e.g. file_watcher) but its inline config object is missing a required field such as certificate_file/private_key_file/ca_certificate_file, or passes a value with the wrong type. Unknown plugin names are silently skipped, so this error only appears for recognized plugins whose ParseConfig returns an error.

Common situations: Switching from system-roots to mTLS and forgetting to add certificate_file + private_key_file to the file_watcher config; referencing a cert path that the schema expects as a nested object; mismatch between the file_watcher schema version and the bootstrap format.

Understand the failure class

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/dd6061c872a588ee. Report an issue: GitHub.