grpc/grpc-go · error
delegating_resolver: unable to build the resolver for target
Error message
delegating_resolver: unable to build the resolver for target %s: %v
What it means
After the proxy URL is resolved (or found unnecessary), the delegating resolver constructs the actual target resolver by calling targetResolverBuilder.Build(target, wcc, opts) at delegatingresolver.go:157. If the underlying scheme-specific resolver (dns, passthrough, unix, etc.) fails to build, New() wraps and returns the error.
Solutions
- Read the wrapped %v to identify which child resolver failed and why.
- Validate the dial target string conforms to the scheme's expectations (e.g. "unix:///path/to/socket", "dns:///host:port").
- If using a custom resolver via grpc.WithResolvers, ensure its Build does not error for the given target.
- Test the target with the scheme's resolver directly to isolate the failure.
Example fix
// before:
// conn, err := grpc.Dial("unix://localhost/tmp/x.sock", opts)
// // unix resolver rejects non-empty authority "localhost"
// after:
// conn, err := grpc.Dial("unix:///tmp/x.sock", opts) Defensive patterns
Strategy: try-catch
Validate before calling
// If you register a custom resolver, smoke-test its Build before relying on
// it in production.
//
// b := resolver.Get(scheme)
// if b == nil { log.Fatalf("no resolver registered for scheme %q", scheme) }
// r, err := b.Build(target, cc, opts)
// if err != nil { log.Fatalf("resolver build failed: %v", err) }
// r.Close() Try / catch
// Dial surfaces the wrapped build error synchronously.
//
// conn, err := grpc.Dial(target, opts)
// if err != nil {
// return fmt.Errorf("dial %s failed: %w", target, err)
// } Prevention
- Validate the dial target against the scheme's expected format (unix path, dns host:port).
- Unit-test custom resolvers' Build for the targets they will receive.
- Log the exact target string when dial failures occur.
When it happens
Trigger: Triggered when targetResolverBuilder.Build returns a non-nil error during delegatingresolver.New while a proxy is configured (so the delegating resolver is in use) and target resolution is enabled.
Common situations: The scheme-specific resolver rejects the target (e.g. unix resolver sees a non-empty authority), a custom resolver registered via grpc.WithResolvers fails, or the target URI is malformed for the chosen scheme.
Related errors
- delegating_resolver: failed to determine proxy URL for…
- delegating_resolver: invalid target address
- missing address
- missing port after port-separator colon
- delegating_resolver: unable to build the proxy resolver
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/477117fd0cb393e1.
Report an issue: GitHub.
Appendix: source
Thrown at internal/resolver/delegatingresolver/delegatingresolver.go:158
r.childMu.Lock()
defer r.childMu.Unlock()
// When the scheme is 'dns' and target resolution on client is not enabled,
// resolution should be handled by the proxy, not the client. Therefore, we
// bypass the target resolver and store the unresolved target address.
if target.URL.Scheme == "dns" && !targetResolutionEnabled {
r.targetResolverState = &resolver.State{
Addresses: []resolver.Address{{Addr: addr}},
Endpoints: []resolver.Endpoint{{Addresses: []resolver.Address{{Addr: addr}}}},
}
r.updateTargetResolverState(*r.targetResolverState)
return r, nil
}
wcc := &wrappingClientConn{
stateListener: r.updateTargetResolverState,
parent: r,
}
if r.targetResolver, err = targetResolverBuilder.Build(target, wcc, opts); err != nil {
return nil, fmt.Errorf("delegating_resolver: unable to build the resolver for target %s: %v", target, err)
}
return r, nil
}
// proxyURIResolver creates a resolver for resolving proxy URIs using the "dns"
// scheme. It adjusts the proxyURL to conform to the "dns:///" format and builds
// a resolver with a wrappingClientConn to capture resolved addresses.
func (r *delegatingResolver) proxyURIResolver(opts resolver.BuildOptions) (resolver.Resolver, error) {
proxyBuilder := resolver.Get("dns")
if proxyBuilder == nil {
panic("delegating_resolver: resolver for proxy not found for scheme dns")
}
url := *r.proxyURL
url.Scheme = "dns"
url.Path = "/" + r.proxyURL.Host
url.Host = "" // Clear the Host field to conform to the "dns:///" format
proxyTarget := resolver.Target{URL: url}View on GitHub (pinned to 0c51461d27)