grpc/grpc-go · error

lrsclient: failed to create transport for server identifier

Error message

lrsclient: failed to create transport for server identifier %s: %v

What it means

Returned by LRSClient.ReportLoad (via getOrCreateLRSStream) when the configured TransportBuilder.Build(serverIdentifier) fails. It is a hard error returned to the caller, not internally retried, because transport construction is a prerequisite to opening any stream.

Source

Thrown at internal/xds/clients/lrsclient/lrsclient.go:120

	// Use an existing stream, if one exists for this server identifier.
	if s, ok := c.lrsStreams[serverIdentifier]; ok {
		if c.logger.V(2) {
			c.logger.Infof("Reusing an existing lrs stream for server identifier %q", serverIdentifier)
		}
		c.lrsRefs[serverIdentifier]++
		return s, nil
	}

	if c.logger.V(2) {
		c.logger.Infof("Creating a new lrs stream for server identifier %q", serverIdentifier)
	}

	// Create a new transport and create a new lrs stream, and add it to the
	// map of lrs streams.
	tr, err := c.transportBuilder.Build(serverIdentifier)
	if err != nil {
		return nil, fmt.Errorf("lrsclient: failed to create transport for server identifier %s: %v", serverIdentifier, err)
	}

	nodeProto := clientsinternal.NodeProto(c.node)
	nodeProto.ClientFeatures = []string{clientFeatureNoOverprovisioning, clientFeatureResourceWrapper}
	lrs := newStreamImpl(streamOpts{
		transport: tr,
		backoff:   c.backoff,
		nodeProto: nodeProto,
		logPrefix: clientPrefix(c),
	})

	// Register a stop function that decrements the reference count, stops
	// the LRS stream when the last reference is removed and closes the
	// transport and removes the lrs stream and its references from the
	// respective maps. Before closing the stream, it waits for the provided
	// context to be done (timeout or cancellation).
	stop := func(ctx context.Context) {
		c.mu.Lock()

View on GitHub (pinned to 03255a9237)

Solutions

  1. Validate the ServerIdentifier (ServerURI reachable, Authority set) before calling ReportLoad.
  2. Inspect the wrapped %v: dial errors mean DNS/network, permission errors mean credentials, config errors mean the builder rejected inputs.
  3. Ensure the TransportBuilder was constructed with credentials matching the server (e.g. xds.Credentials for TLS).
  4. Handle the returned error from ReportLoad rather than ignoring it, since it is not retried by the client.

Example fix

// before
ls, err := c.ReportLoad(si)
if err != nil { log.Fatal(err) }

// after: pre-validate and degrade gracefully
ls, err := c.ReportLoad(si)
if err != nil {
    logger.Warnf("LRS transport unavailable for %s: %v", si.ServerURI, err)
    return // skip load reporting; app traffic continues
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate the server identifier is buildable before ReportLoad.
func validateServerID(b clients.TransportBuilder, si clients.ServerIdentifier) error {
    tr, err := b.Build(si)
    if err != nil { return err }
    tr.Close()
    return nil
}

Try / catch

ls, err := c.ReportLoad(si)
if err != nil {
    // hard error: not retried by the client
    logger.Errorf("cannot start LRS for %s: %v", si.ServerURI, err)
    return
}

Prevention

When it happens

Trigger: ReportLoad is called with a ServerIdentifier whose URI cannot be resolved, whose credentials/transport security cannot be established, or for which the transport builder rejects the config. The first ReportLoad for a given server identifier triggers a new transport; subsequent calls reuse the existing one.

Common situations: Bad ServerURI, missing or malformed credentials in the TransportBuilder, an unresolvable DNS name, or a custom TransportBuilder that returns an error on authority/URI validation.

Related errors


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