grpc/grpc-go · error

xds: failed to create a new channel for server config %v: %v

Error message

xds: failed to create a new channel for server config %v: %v

What it means

Returned when newXDSChannel returns an error inside getOrCreateChannel. newXDSChannel only fails if one of its required opts (transport, serverConfig, clientConfig, eventHandler) is nil — all of which are supplied internally by getOrCreateChannel, so in practice this indicates an internal invariant violation rather than a user config problem.

Source

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

	if err != nil {
		return nil, func() {}, fmt.Errorf("xds: failed to create transport for server config %v: %v", serverConfig, err)
	}
	state := &channelState{
		parent:                c,
		serverConfig:          serverConfig,
		interestedAuthorities: make(map[*authority]bool),
	}
	channel, err := newXDSChannel(xdsChannelOpts{
		transport:          tr,
		serverConfig:       serverConfig,
		clientConfig:       c.config,
		eventHandler:       state,
		backoff:            c.backoff,
		watchExpiryTimeout: c.watchExpiryTimeout,
		logPrefix:          clientPrefix(c),
	})
	if err != nil {
		return nil, func() {}, fmt.Errorf("xds: failed to create a new channel for server config %v: %v", serverConfig, err)
	}
	state.channel = channel
	c.xdsActiveChannels[*serverConfig] = state
	initLocked(state)
	return state.channel, c.releaseChannel(serverConfig, state, deInitLocked), nil
}

// releaseChannel is a function that is called when a reference to an xdsChannel
// needs to be released. It handles closing channels with no active references.
//
// The function takes the following parameters:
// - serverConfig: the server configuration for the xdsChannel
// - state: the state of the xdsChannel
// - deInitLocked: a function that performs any necessary cleanup for the xdsChannel
//
// The function returns another function that can be called to release the
// reference to the xdsChannel. This returned function is idempotent, meaning
// it can be called multiple times without any additional effect.

View on GitHub (pinned to 03255a9237)

Solutions

  1. Ensure Config passed to xdsclient.New has non-nil Servers/Authorities with fully populated ServerConfig values.
  2. If writing custom code that touches the channel layer, never pass nil transport/serverConfig/clientConfig/eventHandler.
  3. Treat this as a bug to report upstream if hit through the public New/WatchResource API.
Defensive patterns

Strategy: validation

Validate before calling

// Ensure Config.Servers/Authorities entries are non-nil and populated.
func validateConfigShape(cfg xdsclient.Config) error {
    for _, s := range cfg.Servers { if s == nil { return errors.New("nil ServerConfig in Servers") } }
    for _, a := range cfg.Authorities {
        if a == nil { return errors.New("nil Authority") }
        for _, s := range a.XDSServers { if s == nil { return errors.New("nil ServerConfig in Authority") } }
    }
    return nil
}

Prevention

When it happens

Trigger: Effectively unreachable through normal API use; would require nil serverConfig/clientConfig being passed into getOrCreateChannel, which the caller (getChannelForADS) guards against via the config construction path.

Common situations: Seen only with a malformed/nil Config (e.g. Servers or Authorities entries with nil pointers) passed to xdsclient.New, or a bug in custom code that calls getOrCreateChannel with nil fields.

Related errors


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