juanfont/headscale · error
tag owner is not an Alias
Error message
tag owner is not an Alias
What it means
Returned while resolving tag owners (hscontrol/policy/v2/policy.go:1750-1752) when a flattened tag owner is neither a Username, Group, nor any other Alias type. The code comment marks it 'Should never happen' — after flattening, all owners must be Alias implementations — so hitting it indicates an internal invariant break, not a user config error.
Source
Thrown at hscontrol/policy/v2/policy.go:29
"strings"
"sync"
"time"
"github.com/juanfont/headscale/hscontrol/policy/matcher"
"github.com/juanfont/headscale/hscontrol/policy/policyutil"
"github.com/juanfont/headscale/hscontrol/types"
"github.com/puzpuzpuz/xsync/v4"
"github.com/rs/zerolog/log"
"go4.org/netipx"
"tailscale.com/net/tsaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/views"
"tailscale.com/util/deephash"
"tailscale.com/util/multierr"
)
// ErrInvalidTagOwner is returned when a tag owner is not an [Alias] type.
var ErrInvalidTagOwner = errors.New("tag owner is not an Alias")
type PolicyManager struct {
// RWMutex, not Mutex, so concurrent map generation does not serialise on
// reads. The per-node caches are xsync.Maps so a read can fill them without
// taking the write lock.
mu sync.RWMutex
pol *Policy
users []types.User
nodes views.Slice[types.NodeView]
filterHash deephash.Sum
filter []tailcfg.FilterRule
matchers []matcher.Match
tagOwnerMapHash deephash.Sum
tagOwnerMap map[Tag]*netipx.IPSet
exitSetHash deephash.SumView on GitHub (pinned to 565fd254d0)
Solutions
- If running a stock release, report it upstream with the full policy — it is a bug
- In forks: ensure every owner added to tagOwners is flattened into an Alias before resolveTagOwners runs, and add the case to the switch
Defensive patterns
Strategy: try-catch
Try / catch
if errors.Is(err, ErrInvalidTagOwner) { // internal invariant break: capture the policy and report upstream; do not attempt config-side fixes } Prevention
- In forks, add a unit test asserting every owner type flattens to Alias before resolveTagOwners
- Run policy tests when vendoring new headscale versions
When it happens
Trigger: A tagOwners map entry resolves to a non-Alias value at compile time. In the current tree this requires a code path that inserts a non-Alias owner (e.g. a new owner type added without updating the flatten step) — no valid policy file can trigger it directly.
Common situations: Custom forks adding new alias/owner types to policy/v2; headscale version skew where policy structs changed; effectively unreachable on stock releases.
Related errors
- auto approver is not an alias
- invalid action
- test(s) failed
- autogroup:self requires per-node resolution and cannot be re
- references undefined tag
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/9bde0e7bb21b9894.
Report an issue: GitHub.