grpc/grpc-go · error
provider(%q, %q).Build(%v) failed
Error message
provider(%q, %q).Build(%v) failed
What it means
BuildableConfig.Build() invokes the provider's starter function to create a Provider instance; if the starter returns nil, Build returns this error. The starter is set by the plugin's ParseConfig; for the bundled pemfile plugin newProvider never returns nil, so this is effectively a plugin-author bug or a third-party provider whose factory deliberately returned nil (e.g. internal preconditions not met).
Source
Thrown at credentials/tls/certprovider/store.go:160
// invocations of this method with the same opts will result in provider
// instances being reused.
func (bc *BuildableConfig) Build(opts BuildOptions) (Provider, error) {
provStore.mu.Lock()
defer provStore.mu.Unlock()
sk := storeKey{
name: bc.name,
config: string(bc.config),
opts: opts,
}
if wp, ok := provStore.providers[sk]; ok {
wp.refCount++
return newSingleCloseWrappedProvider(wp), nil
}
provider := bc.starter(opts)
if provider == nil {
return nil, fmt.Errorf("provider(%q, %q).Build(%v) failed", sk.name, sk.config, opts)
}
wp := &wrappedProvider{
Provider: provider,
refCount: 1,
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 registeredView on GitHub (pinned to 03255a9237)
Solutions
- If you are the plugin author: audit the starter function for any path that returns nil and return a real error instead so the failure is diagnosable.
- If you are a user: upgrade or patch the offending provider plugin; verify BuildOptions (CertName, WantRoot, WantIdentity) match what the provider supports.
- Switch to the bundled file_watcher or another supported provider name for which Build is guaranteed non-nil.
Example fix
// before (custom plugin)
starter := func(o certprovider.BuildOptions) certprovider.Provider {
if !o.WantIdentity { return nil } // -> Build() failed
return newProv(o)
}
// after
starter := func(o certprovider.BuildOptions) certprovider.Provider {
return newProv(o) // never return nil; surface errors at Build via a wrapping provider Defensive patterns
Strategy: try-catch
Try / catch
p, err := bc.Build(opts)
if err != nil {
return fmt.Errorf("provider %s build failed (starter returned nil): %w", bc.String(), err)
} Prevention
- If you author a provider plugin, never return nil from the starter; return a real error.
- Cover every BuildOptions combination in provider tests so no path yields nil.
- Pin to a known-good provider version in go.mod.
When it happens
Trigger: A custom registered certprovider plugin whose starter closure returns nil for certain BuildOptions; a forked provider whose newProvider has an unhandled early-return path.
Common situations: Writing a custom certificate provider plugin and forgetting to return the constructed provider; an Options combo that the provider does not support leading to a nil return.
Related errors
- pemfile: certificate and key file must be in the same direct
- provider instance is closed
- rls: json marshal failed for child policy config {%+v}: %v
- meshca: unsupported config type: %T
- pemfile: json.Unmarshal(%s) failed: %v
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/edb055eb5a5134a2.
Report an issue: GitHub.