{"record":{"id":"aad2065b9e5c1693","repo":"juanfont/headscale","slug":"port-number-out-of-range","errorCode":null,"errorMessage":"port number out of range","messagePattern":"port number out of range","errorType":"validation","errorClass":"ErrPortNumberOutOfRange","httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/utils.go","lineNumber":23,"sourceCode":"\t\"fmt\"\n\t\"net/netip\"\n\t\"slices\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"tailscale.com/tailcfg\"\n)\n\n// Port parsing errors.\nvar (\n\tErrInputMissingColon      = errors.New(\"input must contain a colon character separating destination and port\")\n\tErrInputStartsWithColon   = errors.New(\"input cannot start with a colon character\")\n\tErrInputEndsWithColon     = errors.New(\"input cannot end with a colon character\")\n\tErrInvalidPortRangeFormat = errors.New(\"invalid port range format\")\n\tErrPortRangeInverted      = errors.New(\"invalid port range: first port is greater than last port\")\n\tErrPortMustBePositive     = errors.New(\"first port must be >0, or use '*' for wildcard\")\n\tErrInvalidPortNumber      = errors.New(\"invalid first integer\")\n\tErrPortNumberOutOfRange   = errors.New(\"port number out of range\")\n\tErrBracketsNotIPv6        = errors.New(\"square brackets are only valid around IPv6 addresses\")\n)\n\n// splitDestinationAndPort takes an input string and returns the destination and port as a tuple, or an error if the input is invalid.\n// It supports two bracketed IPv6 forms:\n//   - \"[addr]:port\" (RFC 3986, e.g. \"[::1]:80\")\n//   - \"[addr]/prefix:port\" (e.g. \"[fd7a::1]/128:80,443\")\n//\n// Brackets are only accepted around IPv6 addresses, not IPv4, hostnames, or other alias types.\n// Bracket stripping reduces both forms to bare \"addr:port\" or \"addr/prefix:port\",\n// which the normal [strings.LastIndex] of \":\" split handles correctly because\n// port strings never contain colons.\nfunc splitDestinationAndPort(input string) (string, string, error) {\n\t// Handle RFC 3986 bracketed IPv6 (e.g. \"[::1]:80\" or \"[fd7a::1]/128:80,443\").\n\t// Strip brackets after validation and fall through to normal parsing.\n\tif strings.HasPrefix(input, \"[\") {\n\t\tcloseBracket := strings.Index(input, \"]\")\n\t\tif closeBracket == -1 {","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/utils.go#L5-L41","documentation":"ErrPortNumberOutOfRange is returned by parsePort (hscontrol/policy/v2/utils.go:146) when a token parses as an integer but falls outside the 0-65535 range ports fit in a uint16. Values like 70000, 99999, or negatives are rejected. (Note single port 0 that reaches the range check passes here but is later rejected by ErrPortMustBePositive in parsePortRange.)","triggerScenarios":"Dst port sections like \"host:70000\" or \"host:65536\". Raised when strconv.Atoi succeeds and port < 0 || port > 65535.","commonSituations":"Typos adding extra digits (\"44333\" meant \"443\"); assuming arbitrary integer ranges work; converting configs from systems with different port semantics; template arithmetic producing oversized values.","solutions":["Correct the port to a value in 1-65535","For the upper bound remember 65535 is the max, not 65536","Re-check the rule for other typos — an extra digit usually indicates a rushed edit"],"exampleFix":"// before\n\"dst\": [\"tag:web:44333\"]\n// after\n\"dst\": [\"tag:web:443\"]","handlingStrategy":"validation","validationCode":"func portInRange(tok string) bool {\n    n, err := strconv.Atoi(tok)\n    return err == nil && n >= 0 && n <= 65535\n}","typeGuard":null,"tryCatchPattern":"if errors.Is(err, policyv2.ErrPortNumberOutOfRange) {\n    // correct the port to 1-65535; look for accidental extra digits\n}","preventionTips":["Ports are uint16: max 65535","Extra digits usually mean a typo — re-read the rule"],"tags":["policy","acl","parsing","ports"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}