{"record":{"id":"d4bdf73bb4bd095a","repo":"tailscale/tailscale","slug":"invalid-listen-addr-q-host-part-must-be-empty-or","errorCode":null,"errorMessage":"invalid Listen addr %q; host part must be empty or IP literal","messagePattern":"invalid Listen addr %q; host part must be empty or IP literal","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tsnet/tsnet.go","lineNumber":2039,"sourceCode":"\tvar zero netip.AddrPort\n\thost, portStr, err := net.SplitHostPort(addr)\n\tif err != nil {\n\t\treturn zero, fmt.Errorf(\"tsnet: %w\", err)\n\t}\n\tport, err := net.LookupPort(network, portStr)\n\tif err != nil || port < 0 || port > math.MaxUint16 {\n\t\t// LookupPort returns an error on out of range values so the bounds\n\t\t// checks on port should be unnecessary, but harmless. If they do\n\t\t// match, worst case this error message says \"invalid port: <nil>\".\n\t\treturn zero, fmt.Errorf(\"invalid port: %w\", err)\n\t}\n\tif host == \"\" {\n\t\treturn netip.AddrPortFrom(netip.Addr{}, uint16(port)), nil\n\t}\n\n\tbindHostOrZero, err := netip.ParseAddr(host)\n\tif err != nil {\n\t\treturn zero, fmt.Errorf(\"invalid Listen addr %q; host part must be empty or IP literal\", host)\n\t}\n\t// Normalize unspecified addresses (0.0.0.0, ::) to the zero value,\n\t// equivalent to an empty host, so they match the node's own IPs.\n\tif bindHostOrZero.IsUnspecified() {\n\t\treturn netip.AddrPortFrom(netip.Addr{}, uint16(port)), nil\n\t}\n\tif strings.HasSuffix(network, \"4\") && !bindHostOrZero.Is4() {\n\t\treturn zero, fmt.Errorf(\"invalid non-IPv4 addr %v for network %q\", host, network)\n\t}\n\tif strings.HasSuffix(network, \"6\") && !bindHostOrZero.Is6() {\n\t\treturn zero, fmt.Errorf(\"invalid non-IPv6 addr %v for network %q\", host, network)\n\t}\n\treturn netip.AddrPortFrom(bindHostOrZero, uint16(port)), nil\n}\n\n// ephemeral port range for non-TUN listeners requesting port 0. This range is\n// chosen to reduce the probability of collision with host listeners, avoiding\n// both the typical ephemeral range, and privilege listener ranges. Collisions","sourceCodeStart":2021,"sourceCodeEnd":2057,"githubUrl":"https://github.com/tailscale/tailscale/blob/57c3357fdb542d26c6f9e9f0b815ae5077e63d77/tsnet/tsnet.go#L2021-L2057","documentation":"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.","triggerScenarios":"Thrown at tsnet/tsnet.go:2002 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["Leave the host empty to listen on all of the node's Tailscale IPs","Use the node's Tailscale IPv4 or IPv6 literal as the host"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"57c3357fdb542d26c6f9e9f0b815ae5077e63d77","analyzedAt":"2026-08-18T08:17:25.280Z","contentChangedAt":"2026-08-18T08:17:25.280Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}