{"record":{"id":"76cd3e6d58a6572d","repo":"juanfont/headscale","slug":"invalid-destination-q-w","errorCode":null,"errorMessage":"invalid destination %q: %w","messagePattern":"invalid destination %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"hscontrol/policy/v2/test.go","lineNumber":349,"sourceCode":"\t}\n\n\tif addrs == nil || addrs.Empty() {\n\t\treturn nil, nil\n\t}\n\n\treturn addrs.Prefixes(), nil\n}\n\n// evalReachability reports whether traffic from any srcPrefix to dst (in\n// `host:port` form) is allowed by filter for the requested protocol.\n//\n// Empty proto means the default set the client applies when proto is\n// omitted (TCP/UDP/ICMP) — we accept a rule whose IPProto list contains\n// any of those, or rules with no IPProto restriction at all.\nfunc evalReachability(srcPrefixes []netip.Prefix, dst string, proto Protocol, pol *Policy, filter []tailcfg.FilterRule, users []types.User, nodes views.Slice[types.NodeView]) (bool, error) {\n\tawp, err := parseDestinationAlias(dst)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"invalid destination %q: %w\", dst, err)\n\t}\n\n\tdstAddrs, err := awp.Resolve(pol, users, nodes)\n\tif err != nil {\n\t\treturn false, fmt.Errorf(\"resolving destination: %w\", err)\n\t}\n\n\tif dstAddrs == nil || dstAddrs.Empty() {\n\t\treturn false, fmt.Errorf(\"%w: %q\", errTestDestinationNoIP, dst)\n\t}\n\n\tdstPrefixes := dstAddrs.Prefixes()\n\n\t// Tailscale's tests semantics: ALL src prefixes must reach the dst for\n\t// the test to consider it allowed. A partial allow is a fail.\n\tfor _, src := range srcPrefixes {\n\t\tif !srcReachesDst(src, dstPrefixes, awp.Ports, proto, filter) {\n\t\t\treturn false, nil","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/test.go#L331-L367","documentation":"In the policy-test evaluator, the destination string of an accept/deny check (host:port form) failed parseDestinationAlias. The destination is syntactically invalid: malformed port range, missing ':', or an alias component that does not parse.","triggerScenarios":"A test entry like \"web:80-\" , \"web:\" , \"10.0.0.1:99999\", or \"web:80:443\" (multiple colons). parseDestinationAlias(dst) returns an error inside evalReachability.","commonSituations":"Hand-writing test destinations and using a comma where a colon is expected (\"web,80\"), open-ended port ranges, ports outside 0-65535, or extra colons from copy-pasting IPv6 addresses without brackets.","solutions":["Rewrite the destination as 'alias:port' or 'alias:port-port', e.g. 'web:80' or 'web:8080-8090'.","Ensure every port is in 0-65535 and ranges are 'low-high' with low <= high.","For multiple ports use a comma-separated list of destinations ('web:80, web:443'), not multiple colons.","For IPv6 destinations, use the canonical form accepted by the alias parser (a hosts-map name or a documented prefix form), never a bare '::'-style literal with a port."],"exampleFix":"// before\n\"accept\": [\"web:80,443\"]\n\n// after\n\"accept\": [\"web:80\", \"web:443\"]","handlingStrategy":"validation","validationCode":"// Validate test destinations before running the suite.\nvar dstRe = regexp.MustCompile(`^[^:]+:[0-9]+(-[0-9]+)?$`)\nif !dstRe.MatchString(dst) {\n    return fmt.Errorf(\"bad test destination %q, want alias:port[-port]\", dst)\n}","typeGuard":null,"tryCatchPattern":"if err := runPolicyTests(...); err != nil {\n    if strings.Contains(err.Error(), \"invalid destination\") {\n        // rewrite the dst entry as alias:port and re-run once\n    }\n    return err\n}","preventionTips":["Always write destinations as 'alias:port'; one colon per entry.","Use separate entries for extra ports instead of inventing separators.","Add a policy-file linter (HuJSON schema check) to CI."],"tags":["policy","acl","testing","ports","configuration","go"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}