grpc/grpc-go · error

delegating_resolver: invalid target address

Error message

delegating_resolver: invalid target address %q: %v

What it means

When the target URI uses the "dns" scheme, target resolution on the client is disabled, and envconfig.EnableDefaultPortForProxyTarget is true, the delegating resolver calls parseTarget(addr) on the endpoint to normalize it into host:port form (delegatingresolver.go:116-120). If parseTarget rejects the address (empty or trailing colon with no port), New() fails with this wrapped error instead of constructing the resolver.

Solutions

  1. Supply a complete target endpoint with a host and optional port, e.g. "dns:///svc.cluster.local:443" or "dns:///svc.cluster.local".
  2. Remove any trailing colon ("host:") from the target string.
  3. If you do not want the delegating resolver to pre-parse the address, enable target resolution on the client via the appropriate dial option so this code path is skipped.
  4. Disable EnableDefaultPortForProxyTarget if your deployment does not require it.

Example fix

// before:
//   conn, err := grpc.Dial("dns:///host:", opts)
//   // with HTTPS_PROXY set

// after:
//   conn, err := grpc.Dial("dns:///host:443", opts)
Defensive patterns

Strategy: validation

Validate before calling

package main

import (
	"fmt"
	"net"
	"strings"
)

// normalizeDialEndpoint ensures the endpoint is a valid host[:port] before it
// reaches the delegating resolver.
func normalizeDialEndpoint(ep string) (string, error) {
	ep = strings.TrimSpace(ep)
	if ep == "" {
		return "", fmt.Errorf("missing address")
	}
	if strings.HasSuffix(ep, ":") {
		return "", fmt.Errorf("missing port after colon in %q", ep)
	}
	if _, _, err := net.SplitHostPort(ep); err == nil {
		return ep, nil
	}
	return net.JoinHostPort(ep, "443"), nil
}

// func main() { _, _ = normalizeDialEndpoint("host:") }

Try / catch

// Dial returns the error synchronously. Wrap it to give a clearer message.
//
//   conn, err := grpc.Dial(target, opts)
//   if err != nil && strings.Contains(err.Error(), "invalid target address") {
//       return fmt.Errorf("bad dial target %q: %w", target, err)
//   }

Prevention

When it happens

Trigger: Triggered in delegatingresolver.New when target.URL.Scheme=="dns", targetResolutionEnabled is false, EnableDefaultPortForProxyTarget is true, and parseTarget(target.Endpoint()) returns an error — i.e. the endpoint is empty ("missing address") or ends with a colon but no port ("missing port after port-separator colon").

Common situations: A dial target like "dns:///" (no host), "dns:///:" or "dns:///host:" combined with a configured HTTPS_PROXY; the env var GRPC_EXPERIMENTAL_ENABLE_DEFAULT_PORT_FOR_PROXY_TARGET (or default) is enabled; a service discovery layer produced an empty endpoint.

Related errors


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

Appendix: source

Thrown at internal/resolver/delegatingresolver/delegatingresolver.go:119

//     in the target URI or specified by the user using the WithResolvers dial
//     option. As a special case, if the target URI's scheme is "dns" and a
//     proxy is specified using the supported environment variables, the target
//     URI's path portion is used as the resolved address unless target
//     resolution is enabled using the dial option.
func New(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions, targetResolverBuilder resolver.Builder, targetResolutionEnabled bool) (resolver.Resolver, error) {
	r := &delegatingResolver{
		target:         target,
		cc:             cc,
		proxyResolver:  nopResolver{},
		targetResolver: nopResolver{},
	}

	addr := target.Endpoint()
	var err error
	if target.URL.Scheme == "dns" && !targetResolutionEnabled && envconfig.EnableDefaultPortForProxyTarget {
		addr, err = parseTarget(addr)
		if err != nil {
			return nil, fmt.Errorf("delegating_resolver: invalid target address %q: %v", target.Endpoint(), err)
		}
	}

	r.proxyURL, err = proxyURLForTarget(addr)
	if err != nil {
		return nil, fmt.Errorf("delegating_resolver: failed to determine proxy URL for target %q: %v", target, err)
	}

	// proxy is not configured or proxy address excluded using `NO_PROXY` env
	// var, so only target resolver is used.
	if r.proxyURL == nil {
		return targetResolverBuilder.Build(target, cc, opts)
	}

	if logger.V(2) {
		logger.Infof("Proxy URL detected : %s", r.proxyURL)
	}

View on GitHub (pinned to 0c51461d27)