juanfont/headscale · warning
invalid alias: %w
Error message
invalid alias: %w
What it means
Thrown by the policy-test harness in hscontrol/policy/v2/test.go while resolving the 'Src' field of a PolicyTest. parseAlias rejected the source string, meaning it does not match any alias form the policy engine recognizes (user@, group:, tag:, autogroup:, host, CIDR/IP). The test cannot inherit alias semantics because the string is syntactically invalid before resolution even starts.
Source
Thrown at hscontrol/policy/v2/test.go:325
*fail = append(*fail, dst)
}
}
}
check(test.Accept, true, &res.AcceptOK, &res.AcceptFail)
check(test.Deny, false, &res.DenyOK, &res.DenyFail)
return res
}
// resolveTestSource resolves the Src alias of a [PolicyTest] into a slice of
// [netip.Prefix]. [parseAlias] + [Alias.Resolve] cover every alias type the rest
// of the policy engine supports, so tests inherit alias semantics for free.
func resolveTestSource(src string, pol *Policy, users []types.User, nodes views.Slice[types.NodeView]) ([]netip.Prefix, error) {
alias, err := parseAlias(src)
if err != nil {
return nil, fmt.Errorf("invalid alias: %w", err)
}
addrs, err := alias.Resolve(pol, users, nodes)
if err != nil {
return nil, fmt.Errorf("resolving: %w", err)
}
if addrs == nil || addrs.Empty() {
return nil, nil
}
return addrs.Prefixes(), nil
}
// evalReachability reports whether traffic from any srcPrefix to dst (in
// `host:port` form) is allowed by filter for the requested protocol.
//
// Empty proto means the default set the client applies when proto isView on GitHub (pinned to 565fd254d0)
Solutions
- Check the Src string in the failing test entry against the alias forms: 'user@email', 'group:name', 'tag:name', 'autogroup:self|member|internet|tagged|danger-all', a hostname from the hosts section, or a valid CIDR like '10.0.0.1/32'.
- If the source is a username, make sure it contains '@'; if a tag or group, make sure the prefix and a non-empty name are present.
- Run the policy file through headscale's policy loader (or 'headscale policy check' / unit TestPolicy) to surface the exact parseAlias error wrapped behind 'invalid alias:'.
- If you believe the string is valid, verify you are on a headscale version that supports that alias type (e.g. autogroup:danger-all was added later).
Example fix
// before (in policy tests block)
"tests": [{"src": "alice", "accept": ["web:80"]}]
// after
"tests": [{"src": "alice@example.com", "accept": ["web:80,443"]}] Defensive patterns
Strategy: validation
Validate before calling
// Before adding a PolicyTest, confirm the Src parses as an alias.
import "github.com/juanfont/headscale/hscontrol/policy/v2"
if _, err := v2.ParseAliasForTest(src); err != nil { // or expose parseAlias via a helper
return fmt.Errorf("test src %q is not a valid alias: %w", src, err)
} Try / catch
if err := runPolicyTests(pol, users, nodes); err != nil {
// err wraps 'invalid alias: <cause>'; surface cause, do not retry
log.Error().Err(err).Msg("policy test src invalid")
return err
} Prevention
- Keep a lint step that runs the policy test suite (headscale policy check / go test ./hscontrol/policy/...) in CI for every ACL change.
- Copy Src formats from working entries: 'user@domain', 'group:x', 'tag:x', 'autogroup:self', '100.64.0.0/24'.
- Never hand-type autogroup names; paste them from the version's docs.
When it happens
Trigger: A policy test block (the 'tests' section of a HuJSON/JSON policy) contains a Src value like 'userwithoutat', 'tag:', 'group', '10.0.0.0' (host bits set without a valid mask), or a typo such as 'autogroup:member '. resolveTestSource calls parseAlias(src) and it returns an error.
Common situations: Writing new policy tests by copying examples and forgetting the @ in a username, omitting the tag:/group: prefix, trailing whitespace, or using an IP without a prefix length. Also appears after upgrading headscale when alias grammar was tightened (e.g. stricter autogroup names).
Related errors
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/c752f3270e736b9d.
Report an issue: GitHub.