grpc/grpc-go · error

no certificate provider builder found for %q

Error message

no certificate provider builder found for %q

What it means

certprovider.ParseConfig(name, config) looked up a builder for `name` in the global registry and found none. Builders self-register via certprovider.Register in their init() (e.g. the pemfile plugin registers "file_watcher"), so an unknown name means the plugin package was never imported or the name is misspelled.

Source

Thrown at credentials/tls/certprovider/store.go:183

		storeKey: sk,
		store:    provStore,
	}
	provStore.providers[sk] = wp
	return newSingleCloseWrappedProvider(wp), nil
}

// String returns the provider name and config as a colon separated string.
func (bc *BuildableConfig) String() string {
	return fmt.Sprintf("%s:%s", bc.name, string(bc.config))
}

// ParseConfig is a convenience function to create a BuildableConfig given a
// provider name and configuration. Returns an error if there is no registered
// builder for the given name or if the config parsing fails.
func ParseConfig(name string, config any) (*BuildableConfig, error) {
	parser := getBuilder(name)
	if parser == nil {
		return nil, fmt.Errorf("no certificate provider builder found for %q", name)
	}
	return parser.ParseConfig(config)
}

// GetProvider is a convenience function to create a provider given the name,
// config and build options.
func GetProvider(name string, config any, opts BuildOptions) (Provider, error) {
	bc, err := ParseConfig(name, config)
	if err != nil {
		return nil, err
	}
	return bc.Build(opts)
}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Add the blank import for the provider package, e.g. `import _ "google.golang.org/grpc/credentials/tls/certprovider/pemfile"`.
  2. Verify the exact registered name (pemfile registers PluginName = "file_watcher").
  3. If you wrote a custom provider, ensure certprovider.Register(&yourBuilder{}) runs in an init() of an imported package.

Example fix

// before
import (
    "google.golang.org/grpc/credentials/tls/certprovider"
)
certprovider.ParseConfig("file_watcher", raw)

// after
import (
    "google.golang.org/grpc/credentials/tls/certprovider"
    _ "google.golang.org/grpc/credentials/tls/certprovider/pemfile"
)
certprovider.ParseConfig("file_watcher", raw)
Defensive patterns

Strategy: validation

Validate before calling

func isProviderRegistered(name string) bool {
    // no public lookup; rely on a build-time check by attempting a no-op ParseConfig
    _, err := certprovider.ParseConfig(name, json.RawMessage(`{}`))
    return err == nil || !strings.Contains(err.Error(), "no certificate provider builder")
}

Try / catch

bc, err := certprovider.ParseConfig(name, raw)
if err != nil {
    if strings.Contains(err.Error(), "no certificate provider builder") {
        return fmt.Errorf("forgot to import provider %q? %w", name, err)
    }
    return err
}

Prevention

When it happens

Trigger: Calling ParseConfig("file_watcher", ...) without an `import _ "google.golang.org/grpc/credentials/tls/certprovider/pemfile"` somewhere in the binary; passing a typo like "filesystem_watcher" or "file-watch"; using a provider name from a different gRPC language.

Common situations: Forgetting the blank import of the provider package; renaming a provider name across versions; conditional imports behind build tags that excluded the provider in the active build.

Understand the failure class

Related errors


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