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 when transportBuilder.Build fails for the given ServerIdentifier (lrsclient.go:120). This wraps the underlying Build error (any of the grpctransport Build errors, or a custom transport builder error) with the offending server identifier for context.

Solutions

  1. Read the wrapped error - it is one of the grpctransport errors (404-409) and names the exact cause.
  2. Validate the ServerIdentifier before calling ReportLoad using the same checks Build performs.
  3. Ensure the TransportBuilder was configured with a Config map whose keys match the ServerIdentifierExtension.ConfigName.
Defensive patterns

Strategy: try-catch

Validate before calling

func validateSI(si clients.ServerIdentifier) error {
    if si.ServerURI == "" { return errors.New("ServerURI empty") }
    if si.Extensions == nil { return errors.New("Extensions nil") }
    if _, ok := si.Extensions.(grpctransport.ServerIdentifierExtension); !ok {
        return errors.New("Extensions wrong type")
    }
    return nil
}

Try / catch

ls, err := lrsClient.ReportLoad(si)
if err != nil && strings.Contains(err.Error(), "failed to create transport for server identifier") {
    // unwrap to find the underlying Build error and fix the SI/config
}

Prevention

When it happens

Trigger: Calling lrsClient.ReportLoad(si) where the configured TransportBuilder returns an error from Build(si). The LRS client does not retry Build; it surfaces the error to the caller.

Common situations: The ServerIdentifier passed to ReportLoad was not constructed correctly (empty URI, missing Extension, unknown ConfigName, nil credentials) - see errors 404-408; the transport is unreachable at construction time; credentials bundle construction failed.

Related errors


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

Appendix: 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 0c51461d27)