grpc/grpc-go · error

missing port after port-separator colon

Error message

missing port after port-separator colon

What it means

Returned by parseTarget when net.SplitHostPort succeeded but the port component is empty, meaning the target ended with a colon and no port (e.g. "host:"). This is distinct from a missing port (which gets the default appended): a trailing colon is an explicit, ambiguous, and therefore invalid form.

Source

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

// An error is returned for empty targets or targets with a trailing colon
// but no port (e.g., "host:").
func parseTarget(target string) (string, error) {
	if target == "" {
		return "", fmt.Errorf("missing address")
	}

	host, port, err := net.SplitHostPort(target)
	if err != nil {
		// If SplitHostPort fails, it's likely because the port is missing.
		// We append the default port and return the result.
		return net.JoinHostPort(target, defaultPort), nil
	}

	// If SplitHostPort succeeds, we check for edge cases.
	if port == "" {
		// A success with an empty port means the target had a trailing colon,
		// e.g., "host:", which is an error.
		return "", fmt.Errorf("missing port after port-separator colon")
	}
	if host == "" {
		// A success with an empty host means the target was like ":80".
		// We default the host to "localhost".
		host = "localhost"
	}
	return net.JoinHostPort(host, port), nil
}

func skipProxy(address resolver.Address) bool {
	// Avoid proxy when network is not tcp.
	networkType, ok := networktype.Get(address)
	if !ok {
		networkType, _ = transport.ParseDialTarget(address.Addr)
	}
	if networkType != "tcp" {
		return true
	}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Either remove the trailing colon or supply a real port: "host:443".
  2. Fix the code/template that emits the colon so it only does so when a port exists.
  3. Validate targets with a host:port check before dialing.

Example fix

// before
target := host + ":" + port // port empty -> "host:"
// after
if port != "" { target = host + ":" + port } else { target = host }
Defensive patterns

Strategy: validation

Validate before calling

if strings.HasSuffix(target, ":") {
    return fmt.Errorf("target %q ends with colon but no port", target)
}

Type guard

func hasValidPortForm(t string) bool {
    if !strings.Contains(t, ":") { return true }
    return !strings.HasSuffix(t, ":")
}

Try / catch

if strings.HasSuffix(target, ":") {
    target = strings.TrimSuffix(target, ":") // recover by dropping stray colon
}
conn, err := grpc.Dial(target, ...)

Prevention

When it happens

Trigger: Target strings like "host:", "[::1]:", or "dns:///host:" where the user typed a colon but no port number after it.

Common situations: String formatting bug that appends ":" unconditionally; template that produces "host:${PORT}" with PORT unset; copy-paste from a URL that included a trailing colon.

Related errors


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