tailscale/tailscale · error

invalid Listen addr %q; host part must be empty or IP litera

Error message

invalid Listen addr %q; host part must be empty or IP literal

What it means

resolveListenAddr accepts an empty host or an IP literal only. The host portion of the listen address could not be parsed as an IP, so it is likely a hostname, which tsnet does not resolve for listen addresses.

Source

Thrown at tsnet/tsnet.go:2039

	var zero netip.AddrPort
	host, portStr, err := net.SplitHostPort(addr)
	if err != nil {
		return zero, fmt.Errorf("tsnet: %w", err)
	}
	port, err := net.LookupPort(network, portStr)
	if err != nil || port < 0 || port > math.MaxUint16 {
		// LookupPort returns an error on out of range values so the bounds
		// checks on port should be unnecessary, but harmless. If they do
		// match, worst case this error message says "invalid port: <nil>".
		return zero, fmt.Errorf("invalid port: %w", err)
	}
	if host == "" {
		return netip.AddrPortFrom(netip.Addr{}, uint16(port)), nil
	}

	bindHostOrZero, err := netip.ParseAddr(host)
	if err != nil {
		return zero, fmt.Errorf("invalid Listen addr %q; host part must be empty or IP literal", host)
	}
	// Normalize unspecified addresses (0.0.0.0, ::) to the zero value,
	// equivalent to an empty host, so they match the node's own IPs.
	if bindHostOrZero.IsUnspecified() {
		return netip.AddrPortFrom(netip.Addr{}, uint16(port)), nil
	}
	if strings.HasSuffix(network, "4") && !bindHostOrZero.Is4() {
		return zero, fmt.Errorf("invalid non-IPv4 addr %v for network %q", host, network)
	}
	if strings.HasSuffix(network, "6") && !bindHostOrZero.Is6() {
		return zero, fmt.Errorf("invalid non-IPv6 addr %v for network %q", host, network)
	}
	return netip.AddrPortFrom(bindHostOrZero, uint16(port)), nil
}

// ephemeral port range for non-TUN listeners requesting port 0. This range is
// chosen to reduce the probability of collision with host listeners, avoiding
// both the typical ephemeral range, and privilege listener ranges. Collisions

View on GitHub (pinned to 57c3357fdb)

Solutions

  1. Leave the host empty to listen on all of the node's Tailscale IPs
  2. Use the node's Tailscale IPv4 or IPv6 literal as the host
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at tsnet/tsnet.go:2002 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of tailscale/tailscale@57c3357fdb (2026-08-18). Data as JSON: /api/errors/d4bdf73bb4bd095a. Report an issue: GitHub.