grpc/grpc-go · error
grpctransport: config
Error message
grpctransport: config %q has nil credentials bundle
What it means
Returned when the Config referenced by ConfigName exists but its Credentials field is nil (grpc_transport.go:106). The Builder needs a non-nil credentials.Bundle to construct DialOptions, so a registered-but-empty config is rejected before dialing.
Solutions
- Ensure tlscreds.NewBundle (or equivalent) succeeds before registering the Config.
- Propagate bundle-construction errors at bootstrap time rather than storing nil.
- Add a startup assertion that every Config in the map has non-nil Credentials.
Example fix
// before
b, _, err := tlscreds.NewBundle(cfg)
// err ignored, b may be nil
builder := grpctransport.NewBuilder(map[string]Config{"mtls": {Credentials: nil}})
// after
b, closeFn, err := tlscreds.NewBundle(cfg)
if err != nil { return err }
builder := grpctransport.NewBuilder(map[string]Config{"mtls": {Credentials: b}}) Defensive patterns
Strategy: validation
Validate before calling
for name, cfg := range configs {
if cfg.Credentials == nil {
return fmt.Errorf("config %q has nil credentials", name)
}
}
builder := grpctransport.NewBuilder(configs) Try / catch
if err != nil && strings.Contains(err.Error(), "nil credentials bundle") {
// build the bundle first, propagate any error, then register
} Prevention
- Always propagate errors from tlscreds.NewBundle; never store a nil bundle.
- Add a startup assertion that every Config has non-nil Credentials.
- Initialize bundles in a single function and fail fast on error.
When it happens
Trigger: grpctransport.NewBuilder is called with a map entry like "mtls": {Credentials: nil}. Build resolves the config successfully then fails the nil check.
Common situations: Config was registered as a placeholder; tlscreds.NewBundle failed earlier and the caller stored a nil bundle instead of propagating the error; the credentials field was omitted in a struct literal.
Related errors
- grpctransport: unknown config name
- grpctransport: Extensions field is %T, but must be %T in…
- grpctransport: Extensions is not set in ServerIdentifier
- grpctransport: failed to create connection to server
- grpctransport: ServerURI is not set in ServerIdentifier
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/8fe0af01e084637d.
Report an issue: GitHub.
Appendix: source
Thrown at internal/xds/clients/grpctransport/grpc_transport.go:106
// The Extension field of the ServerIdentifier must be a ServerIdentifierExtension.
func (b *Builder) Build(si clients.ServerIdentifier) (clients.Transport, error) {
if si.ServerURI == "" {
return nil, fmt.Errorf("grpctransport: ServerURI is not set in ServerIdentifier")
}
if si.Extensions == nil {
return nil, fmt.Errorf("grpctransport: Extensions is not set in ServerIdentifier")
}
sce, ok := si.Extensions.(ServerIdentifierExtension)
if !ok {
return nil, fmt.Errorf("grpctransport: Extensions field is %T, but must be %T in ServerIdentifier", si.Extensions, ServerIdentifierExtension{})
}
config, ok := b.configs[sce.ConfigName]
if !ok {
return nil, fmt.Errorf("grpctransport: unknown config name %q specified in ServerIdentifierExtension", sce.ConfigName)
}
if config.Credentials == nil {
return nil, fmt.Errorf("grpctransport: config %q has nil credentials bundle", sce.ConfigName)
}
b.mu.Lock()
defer b.mu.Unlock()
if cc, ok := b.connections[si]; ok {
if logger.V(2) {
logger.Infof("Reusing existing connection to the server for ServerIdentifier: %v", si)
}
b.refs[si]++
tr := &grpcTransport{cc: cc}
tr.cleanup = b.cleanupFunc(si, tr)
return tr, nil
}
// Create a new gRPC client/channel for the server with the provided
// credentials, server URI, and a byte codec to send and receive messages.
// Also set a static keepalive configuration that is common across gRPCView on GitHub (pinned to 0c51461d27)