grpc/grpc-go · error
rls: unregistered scheme in lookup_service %s
Error message
rls: unregistered scheme in lookup_service %s
What it means
Returned by parseRLSProto (config.go:206-211) when the scheme parsed from lookup_service is not a registered resolver scheme (resolver.Get(scheme) returns nil). gRPC needs a resolver for the scheme to turn the target into endpoints; an unregistered scheme means no resolver can handle it.
Source
Thrown at balancer/rls/config.go:210
// `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:
// - if `max_age` > 5m, it should be set to 5 minutes
// only if stale age is not set
// - if `stale_age` > `max_age`, ignore it
// - if `stale_age` is set, then `max_age` must also be set
maxAgeSet := false
maxAge, err := convertDuration(rlsProto.GetMaxAge())
if err != nil {View on GitHub (pinned to 03255a9237)
Solutions
- Register the resolver for the scheme: add the blank import, e.g. _ "google.golang.org/grpc/xds" or _ "google.golang.org/grpc/balancer/rls" as appropriate, or your custom resolver package.
- Use a scheme that is registered by default (e.g. "dns:///") if you don't need a special resolver.
- If you mistyped the scheme, correct it (note: lookup_service with no scheme is auto-prefixed with the default scheme, so this error implies a non-default, unregistered scheme was present).
Example fix
// before: "xds" resolver not imported, lookup_service = "xds:///rls" import ( _ "google.golang.org/grpc/balancer/rls" ) // after: also import the resolver for the scheme you reference import ( _ "google.golang.org/grpc/balancer/rls" _ "google.golang.org/grpc/xds" // registers the xds resolver ) // or use the default scheme: rlc.LookupService = "dns:///rls.example:443"
Defensive patterns
Strategy: validation
Validate before calling
import "google.golang.org/grpc/resolver"
func validateLookupServiceScheme(svc string) error {
t, err := url.Parse(svc)
if err != nil { return nil } // caught by the URI check
scheme := t.Scheme
if scheme == "" { scheme = resolver.GetDefaultScheme() }
if resolver.Get(scheme) == nil {
return fmt.Errorf("unregistered scheme %s in %s", scheme, svc)
}
return nil
} Prevention
- Blank-import the resolver package for any non-default scheme you reference (e.g. _ "google.golang.org/grpc/xds").
- Prefer the default dns scheme when possible.
- Double-check scheme spelling.
When it happens
Trigger: lookup_service uses a scheme whose resolver is not registered in the client binary, e.g. "xds://..." without the xds resolver imported, or a custom/typo scheme like "grpcs:///".
Common situations: Client binary does not import the side-effect import for the needed resolver (e.g. _ "google.golang.org/grpc/xds" for xds, or a custom resolver package). Typos in the scheme. Control plane using a scheme the client doesn't support.
Related errors
- rls: invalid target URI 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/75002af6c89c9413.
Report an issue: GitHub.