{"record":{"id":"c9bcd14ae919bbfc","repo":"juanfont/headscale","slug":"resolving-w-c9bcd1","errorCode":null,"errorMessage":"resolving: %w","messagePattern":"resolving: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"hscontrol/policy/v2/test.go","lineNumber":330,"sourceCode":"\n\tcheck(test.Accept, true, &res.AcceptOK, &res.AcceptFail)\n\tcheck(test.Deny, false, &res.DenyOK, &res.DenyFail)\n\n\treturn res\n}\n\n// resolveTestSource resolves the Src alias of a [PolicyTest] into a slice of\n// [netip.Prefix]. [parseAlias] + [Alias.Resolve] cover every alias type the rest\n// of the policy engine supports, so tests inherit alias semantics for free.\nfunc resolveTestSource(src string, pol *Policy, users []types.User, nodes views.Slice[types.NodeView]) ([]netip.Prefix, error) {\n\talias, err := parseAlias(src)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid alias: %w\", err)\n\t}\n\n\taddrs, err := alias.Resolve(pol, users, nodes)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"resolving: %w\", err)\n\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 {","sourceCodeStart":312,"sourceCodeEnd":348,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/test.go#L312-L348","documentation":"The Src alias in a PolicyTest parsed successfully but Alias.Resolve failed while turning it into IP prefixes. This wraps resolution errors such as a user not found (ErrUserNotFound), an unknown host (ErrHostResolve), or an unsupported autogroup — the alias is well-formed but does not name anything resolvable in the current policy and user database.","triggerScenarios":"A test Src like 'ghost@example.com' where no user with that email/name exists, 'autogroup:nonroot' (unsupported), or a hostname that is not in the policy's hosts map. alias.Resolve(pol, users, nodes) returns an error after parseAlias succeeded.","commonSituations":"Policy tests reference users that exist in the ACL grants but not in the headscale user database used for the test run; renaming users in the DB but not in tests; using Tailscale-documented autogroups that headscale has not implemented.","solutions":["Identify the wrapped error — it is printed after 'resolving:' and is usually ErrUserNotFound, ErrMultipleUsersFound, ErrHostResolve, or ErrUnknownAutogroup; fix the specific cause.","If Src is a user, confirm the user exists (headscale users list) and that email or username matches exactly.","If Src is a host, confirm it is declared in the 'hosts' section of the same policy file.","Replace unsupported autogroups (e.g. autogroup:nonroot) with an explicit group or tag."],"exampleFix":"// before\n\"tests\": [{\"src\": \"autogroup:nonroot\", \"accept\": [\"api:443\"]}]\n\n// after\n\"tests\": [{\"src\": \"group:teamdev\", \"accept\": [\"api:443\"]}]","handlingStrategy":"validation","validationCode":"// Before running tests, verify each user alias exists in the user set.\nfunc srcUserExists(src string, users types.Users) bool {\n    if !strings.Contains(src, \"@\") { return true } // not a user alias\n    for _, u := range users {\n        if u.Email == src || u.Name == src { return true }\n    }\n    return false\n}","typeGuard":null,"tryCatchPattern":"if err := runPolicyTests(...); err != nil {\n    if errors.Is(err, v2.ErrUserNotFound) || errors.Is(err, v2.ErrHostResolve) || errors.Is(err, v2.ErrUnknownAutogroup) {\n        // resolution-time problem: fix fixture data, not the policy grammar\n    }\n    return err\n}","preventionTips":["Seed test fixtures (users, nodes, hosts) before running policy tests.","Reference groups instead of individual users so renames do not break resolution.","Treat any 'resolving:' wrap as a data-sync issue; read the inner error first."],"tags":["policy","acl","testing","resolution","go"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}