grpc/grpc-go · error

xdsclient: transport builder is nil

Error message

xdsclient: transport builder is nil

What it means

`xdsclient.New` (xdsclient.go:103) requires a non-nil `TransportBuilder` in Config — this is the component the client uses to create transports to each xDS management server. Without it, no ADS stream can ever be opened, so it is rejected at xdsclient.go:107-108.

Source

Thrown at internal/xds/clients/xdsclient/xdsclient.go:108

	// to these channels based on server configs within the authority config.
	// The XDSClient maintains a list of interested authorities for each of
	// these channels, and forwards updates from the channels to each of these
	// authorities.
	//
	// Once all references to a channel are dropped, the channel is closed.
	channelsMu        sync.Mutex
	xdsActiveChannels map[ServerConfig]*channelState // Map from server config to in-use xdsChannels.

	metricsCleanup func()
}

// New returns a new xDS Client configured with the provided config.
func New(config Config) (*XDSClient, error) {
	switch {
	case config.ResourceTypes == nil:
		return nil, errors.New("xdsclient: resource types map is nil")
	case config.TransportBuilder == nil:
		return nil, errors.New("xdsclient: transport builder is nil")
	case config.Authorities == nil && config.Servers == nil:
		return nil, errors.New("xdsclient: no servers or authorities specified")
	}
	if config.WatchExpiryTimeout == 0 {
		config.WatchExpiryTimeout = defaultWatchExpiryTimeout
	}
	client, err := newClient(&config, name)
	if err != nil {
		return nil, err
	}
	// Register this client instance as an Async Reporter.
	if client.metricsReporter != nil {
		reporter := &xdsClientMetricReporter{c: client}
		client.metricsCleanup = client.metricsReporter.RegisterAsyncReporter(reporter)
	}
	return client, nil
}

View on GitHub (pinned to 0c51461d27)

Solutions

  1. Set Config.TransportBuilder to a valid clients.TransportBuilder before calling xdsclient.New.
  2. Verify the builder-creation step succeeded (capture its error) before assembling Config.
  3. Build a Config factory that returns an error if TransportBuilder is nil, rather than relying on xdsclient.New to detect it.

Example fix

// before
cfg := xdsclient.Config{Node: node, ResourceTypes: rts, Servers: servers}
client, err := xdsclient.New(cfg) // err: transport builder is nil

// after
tb, err := clients.NewTransportBuilder(transportOpts)
if err != nil { return err }
cfg := xdsclient.Config{Node: node, ResourceTypes: rts, Servers: servers, TransportBuilder: tb}
client, err := xdsclient.New(cfg)
Defensive patterns

Strategy: validation

Validate before calling

func newXDSClientWithBuilder(node clients.Node, tb clients.TransportBuilder, rts map[string]xdsclient.ResourceType, servers []xdsclient.ServerConfig) (*xdsclient.XDSClient, error) {
    if tb == nil {
        return nil, errors.New("a non-nil TransportBuilder is required")
    }
    return xdsclient.New(xdsclient.Config{Node: node, TransportBuilder: tb, ResourceTypes: rts, Servers: servers})
}

Prevention

When it happens

Trigger: Triggered by `xdsclient.New(config)` with `config.TransportBuilder == nil`. Validation runs before any authority/channel is created.

Common situations: Constructing a Config without initializing the TransportBuilder; an earlier setup step (e.g. dialing a bootstrap-provided transport builder factory) failing silently; copying a Config struct that someone cleared.

Related errors


AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11). Data as JSON: /api/errors/27930e774c40d469. Report an issue: GitHub.