grpc/grpc-go · error

grpctransport: config %q has nil credentials bundle

Error message

grpctransport: config %q has nil credentials bundle

What it means

The Config selected by ConfigName must have a non-nil Credentials bundle (grpc_transport.go:105-106) because the gRPC dial options include grpc.WithCredentialsBundle(config.Credentials). A nil bundle would produce a broken channel, so Build rejects it upfront. The offending config name is reported.

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 gRPC

View on GitHub (pinned to 03255a9237)

Solutions

  1. Set Config.Credentials to a valid credentials.Bundle (e.g. from tlscreds.NewBundle or credentials.NewTLS) before adding it to the map.
  2. If credential creation can fail, handle the error and skip registering that Config rather than registering one with nil Credentials.
  3. Add a precondition loop after building the configs map to assert none have nil Credentials.

Example fix

// before:
//   builder := grpctransport.NewBuilder(map[string]Config{
//     "default": { Credentials: nil },
//   })
// after:
//   bdl, closeFn, err := tlscreds.NewBundle(cfg)
//   if err != nil { return err }
//   builder := grpctransport.NewBuilder(map[string]Config{
//     "default": { Credentials: bdl },
//   })
Defensive patterns

Strategy: validation

Validate before calling

func validateConfigs(configs map[string]grpctransport.Config) error {
    for name, cfg := range configs {
        if cfg.Credentials == nil {
            return fmt.Errorf("config %q has nil Credentials", name)
        }
    }
    return nil
}

Prevention

When it happens

Trigger: A Config entry was added to the NewBuilder map with Config.Credentials left nil. This can happen when the config was partially initialized or a credentials bundle failed to build but the empty Config was still registered.

Common situations: The credentials.Bundle was supposed to be created from tlscreds.NewBundle or similar but the call was omitted or its error ignored; a config was templated in without the credentials step.

Related errors


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