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 is

View on GitHub (pinned to 565fd254d0)

Solutions

  1. 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'.
  2. 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.
  3. 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:'.
  4. 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

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.