grpc/grpc-go · error

invalid target address %v, error info: %v

Error message

invalid target address %v, error info: %v

What it means

Returned by the dns resolver's parseTarget as the final fallback when every parsing attempt fail: the target is not a bare IP, not a valid host:port, and joining it with the default port also fails. This is the catch-all for unparseable target strings passed to the dns resolver.

Source

Thrown at internal/resolver/dns/dns_resolver.go:416

	if host, port, err = net.SplitHostPort(target); err == nil {
		if port == "" {
			// If the port field is empty (target ends with colon), e.g. "[::1]:",
			// this is an error.
			return "", "", internal.ErrEndsWithColon
		}
		// target has port, i.e ipv4-host:port, [ipv6-host]:port, host-name:port
		if host == "" {
			// Keep consistent with net.Dial(): If the host is empty, as in ":80",
			// the local system is assumed.
			host = "localhost"
		}
		return host, port, nil
	}
	if host, port, err = net.SplitHostPort(target + ":" + defaultPort); err == nil {
		// target doesn't have port
		return host, port, nil
	}
	return "", "", fmt.Errorf("invalid target address %v, error info: %v", target, err)
}

type rawChoice struct {
	ClientLanguage *[]string        `json:"clientLanguage,omitempty"`
	Percentage     *int             `json:"percentage,omitempty"`
	ClientHostName *[]string        `json:"clientHostName,omitempty"`
	ServiceConfig  *json.RawMessage `json:"serviceConfig,omitempty"`
}

func containsString(a *[]string, b string) bool {
	if a == nil {
		return true
	}
	for _, c := range *a {
		if c == b {
			return true
		}
	}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Bracket IPv6 literals: "[2001:db8::1]:443".
  2. Pass only host or host:port to the dns target, not a full URL; strip scheme/path.
  3. Use the dns:/// authority form consistently: "dns:///host:port".
  4. Validate the target format before dialing.

Example fix

// before
conn, _ := grpc.Dial("::1:443", ...)        // unparseable
conn, _ := grpc.Dial("https://host:443", ...) // scheme leaks in
// after
conn, _ := grpc.Dial("dns:///[::1]:443", ...)
conn, _ := grpc.Dial("dns:///host:443", ...)
Defensive patterns

Strategy: validation

Validate before calling

// Normalize target before dialing.
func normalizeTarget(t string) string {
    t = strings.TrimSpace(t)
    t = strings.TrimPrefix(t, "https://")
    t = strings.TrimPrefix(t, "http://")
    if strings.Count(t, ":") > 1 && !strings.HasPrefix(t, "[") {
        // Looks like bare IPv6; bracket it.
        host, port, err := net.SplitHostPort(t)
        if err == nil { t = net.JoinHostPort(host, port) }
    }
    return "dns:///" + t
}

Type guard

func looksLikeValidDnsTarget(t string) bool {
    ep := strings.TrimPrefix(t, "dns:///")
    if ep == "" { return false }
    if _, err := netip.ParseAddr(ep); err == nil { return true }
    _, _, err := net.SplitHostPort(ep)
    return err == nil
}

Try / catch

conn, err := grpc.Dial(target, ...)
if err != nil && strings.Contains(err.Error(), "invalid target address") {
    conn, err = grpc.Dial(normalizeTarget(target), ...)
}

Prevention

When it happens

Trigger: Targets with illegal characters for both SplitHostPort and JoinHostPort (e.g. unbracketed raw IPv6 like "::1:443", targets containing spaces or slashes in the host). It is the inner error returned from dnsBuilder.Build and propagated to the caller as a dial failure.

Common situations: Passing an unbracketed IPv6 address (must be "[::1]:443"); copy-paste of a full URL ("https://host") as the target; target containing a path or query fragment.

Related errors


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