grpc/grpc-go · critical

xds: failed to create transport for server config

Error message

xds: failed to create transport for server config %v: %v

What it means

The xDS client's TransportBuilder.Build returned an error when attempting to create a transport (network connection) to the xDS management server identified by the given ServerConfig. This wraps the underlying Build error with the server config for diagnostics, and means no ADS (Aggregated Discovery Service) stream can be established to that server, blocking all resource discovery.

Solutions

  1. Verify the xDS server URI includes host and port and is network-reachable (e.g. test with 'nc -zv host 443')
  2. Check TLS certificate validity and ensure ServerIdentifier.Extensions carries the correct credentials for the TransportBuilder
  3. Inspect the wrapped error in the log — it contains the specific Build failure (DNS resolution, TLS handshake, dial timeout, etc.)
  4. If using a custom TransportBuilder, ensure Build returns (non-nil Transport, nil) for a valid ServerIdentifier
  5. Confirm the xDS management server process is running and accepting connections

Example fix

// before — unreachable server URI, no port
config.Servers = []xdsclient.ServerConfig{{
    ServerIdentifier: clients.ServerIdentifier{ServerURI: "xds-mgmt"},
}}

// after — fully qualified URI with port
config.Servers = []xdsclient.ServerConfig{{
    ServerIdentifier: clients.ServerIdentifier{
        ServerURI:  "xds-mgmt.example.com:443",
        Extensions: tlsCreds,
    },
}}
Defensive patterns

Strategy: validation

Validate before calling

// Validate server reachability before creating the xDS client.
for _, sc := range config.Servers {
    conn, err := net.DialTimeout("tcp", sc.ServerIdentifier.ServerURI, 5*time.Second)
    if err != nil {
        return fmt.Errorf("xDS server %s is unreachable: %w", sc.ServerIdentifier.ServerURI, err)
    }
    conn.Close()
}

Try / catch

client, err := xdsclient.New(config)
if err != nil {
    if strings.Contains(err.Error(), "failed to create transport") {
        // Transport creation failed — inspect wrapped error for network/TLS details.
        // The xDS client may still be usable if other servers in the list succeed.
        log.Printf("xDS transport creation failed for server: %v", err)
    }
    return err
}

Prevention

When it happens

Trigger: Called inside getOrCreateChannel (xdsclient.go:289) when no existing channel matches the server config — typically on the first resource watch or after all channels for a server have been released. The TransportBuilder.Build(serverConfig.ServerIdentifier) call returns a non-nil error (e.g. dial failure, TLS handshake error, unsupported credential type).

Common situations: xDS server URI is unresolvable or points to a wrong port; TLS certificate is expired, self-signed, or from an untrusted CA; firewall or network policy blocks the outbound connection; custom TransportBuilder returns an error due to unsupported ServerIdentifier.Extensions credential configuration; server temporarily down during initial connection attempt.

Related errors


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

Appendix: source

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

	// Use an existing channel, if one exists for this server config.
	if st, ok := c.xdsActiveChannels[*serverConfig]; ok {
		if c.logger.V(2) {
			c.logger.Infof("Reusing an existing xdsChannel for server config %q", serverConfig)
		}
		initLocked(st)
		return st.channel, c.releaseChannel(serverConfig, st, deInitLocked), nil
	}

	if c.logger.V(2) {
		c.logger.Infof("Creating a new xdsChannel for server config %q", serverConfig)
	}

	// Create a new transport and create a new xdsChannel, and add it to the
	// map of xdsChannels.
	tr, err := c.transportBuilder.Build(serverConfig.ServerIdentifier)
	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)
	}

View on GitHub (pinned to 0c51461d27)