grpc/grpc-go · error

xdsclient: resource types map is nil

Error message

xdsclient: resource types map is nil

What it means

`xdsclient.New` (internal/xds/clients/xdsclient/xdsclient.go:103) validates the supplied Config. The `ResourceTypes` field (map[string]ResourceType) is the registry the client uses to parse incoming ADS resources by type URL. Without it the client cannot decode any response, so a nil map is rejected at xdsclient.go:105-106.

Source

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

	// The XDSClient owns a bunch of channels to individual xDS servers
	// specified in the xDS client configuration. Authorities acquire references
	// 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. Populate Config.ResourceTypes with the resource types you need (e.g. xdsresource.ListenerResourceType, ClusterResourceType, etc.) — typically via a helper that returns the standard set.
  2. Ensure the map is non-nil even if empty is not acceptable — at minimum include the listener type.
  3. Centralize Config construction in one factory that always sets ResourceTypes, TransportBuilder, and Servers/Authorities together.

Example fix

// before
cfg := xdsclient.Config{Node: node, TransportBuilder: tb, Servers: servers}
client, err := xdsclient.New(cfg) // err: resource types map is nil

// after
cfg := xdsclient.Config{
    Node: node, TransportBuilder: tb, Servers: servers,
    ResourceTypes: map[string]xdsclient.ResourceType{
        xdsresource.V3ListenerURL: xdsresource.ListenerResourceType{},
        // ...cluster, endpoint, route types
    },
}
client, err := xdsclient.New(cfg)
Defensive patterns

Strategy: validation

Validate before calling

func newXDSClient(cfg xdsclient.Config) (*xdsclient.XDSClient, error) {
    if cfg.ResourceTypes == nil || len(cfg.ResourceTypes) == 0 {
        return nil, errors.New("xdsclient.Config.ResourceTypes must contain at least one ResourceType")
    }
    return xdsclient.New(cfg)
}

Prevention

When it happens

Trigger: Triggered by `xdsclient.New(config)` where `config.ResourceTypes == nil`. The validation at line 105 runs before any connection is attempted.

Common situations: Forgetting to populate ResourceTypes with the standard LDS/RDS/CDS/EDS ResourceType implementations; reusing a Config struct from another context that had the field cleared; building a Config in tests without registering resource types.

Related errors


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