grpc/grpc-go · error

rls: empty lookup_service in route lookup config %+v

Error message

rls: empty lookup_service in route lookup config %+v

What it means

Returned by parseRLSProto (config.go:194-197) when RouteLookupConfig.lookup_service is empty. lookup_service is the RLS server address the policy dials to resolve targets; an empty value leaves RLS unable to function, so it is mandatory per the validation contract documented above ParseConfig.

Source

Thrown at balancer/rls/config.go:196

		return nil, err
	}
	lbCfg.childPolicyName = name
	lbCfg.childPolicyConfig = config
	lbCfg.childPolicyTargetField = cfgJSON.ChildPolicyConfigTargetFieldName
	return lbCfg, nil
}

func parseRLSProto(rlsProto *rlspb.RouteLookupConfig) (*lbConfig, error) {
	// Validations specified on the `grpc_keybuilders` field are performed here.
	kbMap, err := keys.MakeBuilderMap(rlsProto)
	if err != nil {
		return nil, err
	}

	// `lookup_service` field must be set and must parse as a target URI.
	lookupService := rlsProto.GetLookupService()
	if lookupService == "" {
		return nil, fmt.Errorf("rls: empty lookup_service in route lookup config %+v", rlsProto)
	}
	parsedTarget, err := url.Parse(lookupService)
	if err != nil {
		// url.Parse() fails if scheme is missing. Retry with default scheme.
		parsedTarget, err = url.Parse(resolver.GetDefaultScheme() + ":///" + lookupService)
		if err != nil {
			return nil, fmt.Errorf("rls: invalid target URI in lookup_service %s", lookupService)
		}
	}
	if parsedTarget.Scheme == "" {
		parsedTarget.Scheme = resolver.GetDefaultScheme()
	}
	if resolver.Get(parsedTarget.Scheme) == nil {
		return nil, fmt.Errorf("rls: unregistered scheme in lookup_service %s", lookupService)
	}

	lookupServiceTimeout, err := convertDuration(rlsProto.GetLookupServiceTimeout())
	if err != nil {

View on GitHub (pinned to 03255a9237)

Solutions

  1. Set lookup_service to the URI/authority of your RLS server (e.g. "rls.example:443" or "dns:///rls.example:443").
  2. Confirm the control plane populates RouteLookupConfig.lookup_service from the xDS RLS Cluster resource.

Example fix

// before
rlc := &rlspb.RouteLookupConfig{ /* lookup_service missing */ }

// after
rlc := &rlspb.RouteLookupConfig{ LookupService: "dns:///rls.example:443" }
Defensive patterns

Strategy: validation

Validate before calling

func validateLookupService(rlc *rlspb.RouteLookupConfig) error {
    if rlc.GetLookupService() == "" {
        return errors.New("lookup_service must be set")
    }
    return nil
}

Type guard

func hasLookupService(rlc *rlspb.RouteLookupConfig) bool { return rlc.GetLookupService() != "" }

Prevention

When it happens

Trigger: The RouteLookupConfig proto has lookup_service unset/empty (default proto value).

Common situations: Control plane emitting an RLS config before the RLS server address is known. Hand-authored proto with lookup_service omitted.

Related errors


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