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.Sum

View on GitHub (pinned to 565fd254d0)

Solutions

  1. If running a stock release, report it upstream with the full policy — it is a bug
  2. 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

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


AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15). Data as JSON: /api/errors/9bde0e7bb21b9894. Report an issue: GitHub.