grpc/grpc-go · error
rls: invalid target URI in lookup_service %s
Error message
rls: invalid target URI in lookup_service %s
What it means
Returned by parseRLSProto (config.go:198-204) when lookup_service cannot be parsed as a target URI even after prefixing the default scheme (resolver.GetDefaultScheme() + ":///"). url.Parse failed both on the raw value and on the default-scheme-prefixed value, so the string is not a usable dial target.
Source
Thrown at balancer/rls/config.go:203
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 {
return nil, fmt.Errorf("rls: failed to parse lookup_service_timeout in route lookup config %+v: %v", rlsProto, err)
}
if lookupServiceTimeout == 0 {
lookupServiceTimeout = defaultLookupServiceTimeout
}
// Validations performed here:View on GitHub (pinned to 03255a9237)
Solutions
- Provide a clean host[:port] or a fully-qualified target URI for lookup_service (e.g. "dns:///rls.example:443").
- Sanitize the address string and re-test with url.Parse before shipping the config.
- Check the xDS control plane's lookup_service field for corruption.
Example fix
// before rlc.LookupService = "rls example:443" // space makes it un-parseable // after rlc.LookupService = "dns:///rls.example:443"
Defensive patterns
Strategy: validation
Validate before calling
import "net/url"
import "google.golang.org/grpc/resolver"
func validateLookupServiceURI(svc string) error {
t, err := url.Parse(svc)
if err != nil {
t, err = url.Parse(resolver.GetDefaultScheme() + ":///" + svc)
if err != nil {
return fmt.Errorf("invalid target URI %s", svc)
}
}
_ = t
return nil
} Prevention
- Use clean host[:port] or dns:///host:port forms.
- Sanitize addresses before putting them in the config.
When it happens
Trigger: lookup_service contains characters that make it an invalid URI even with a scheme prepended (control characters, malformed escaping). The first url.Parse fails (typically because the scheme is missing), and the retry with the default scheme also fails.
Common situations: Typo or stray characters in the RLS server address. Pasting an address with embedded spaces or unescaped special characters. Control-plane templating bug injecting bad bytes.
Related errors
- rls: unregistered scheme in lookup_service %s
- rls: json unmarshal failed for service config %+v: %v
- rls: bad RouteLookupConfig proto %+v: %v
- rls: bad control channel service config %q: %v
- rls: childPolicyConfigTargetFieldName field is not set in se
AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07).
Data as JSON: /api/errors/678ff82cd0fc3db1.
Report an issue: GitHub.