juanfont/headscale · error
autogroup:self requires per-node resolution and cannot be re
Error message
autogroup:self requires per-node resolution and cannot be resolved in this context
What it means
Returned from alias resolution (hscontrol/policy/v2/types.go:811) when autogroup:self is used where a global, node-independent answer is required. autogroup:self means 'the requesting node's own user', which can only be resolved per-node (e.g. in filter compilation for a specific node); contexts that compile one answer for the whole tailnet cannot honor it.
Source
Thrown at hscontrol/policy/v2/types.go:36
"go4.org/netipx"
"tailscale.com/net/tsaddr"
"tailscale.com/tailcfg"
"tailscale.com/types/views"
"tailscale.com/util/multierr"
"tailscale.com/util/set"
"tailscale.com/util/slicesx"
)
// Global JSON options for consistent parsing across all struct unmarshaling.
var policyJSONOpts = []json.Options{
json.DefaultOptionsV2(),
json.MatchCaseInsensitiveNames(true),
json.RejectUnknownMembers(true),
}
const Wildcard = Asterix(0)
var ErrAutogroupSelfRequiresPerNodeResolution = errors.New("autogroup:self requires per-node resolution and cannot be resolved in this context")
var ErrUndefinedTagReference = errors.New("references undefined tag")
// SSH validation errors.
var (
ErrSSHTagSourceToUserDest = errors.New("tags in SSH source cannot access user-owned devices")
ErrSSHUserDestRequiresSameUser = errors.New("user destination requires source to contain only that same user")
ErrSSHAutogroupSelfRequiresUserSource = errors.New("autogroup:self destination requires source to contain only users or groups, not tags or autogroup:tagged")
ErrSSHTagSourceToAutogroupMember = errors.New("tags in SSH source cannot access autogroup:member (user-owned devices)")
ErrSSHWildcardDestination = errors.New("wildcard (*) is not supported as SSH destination")
ErrSSHCheckPeriodAboveMax = errors.New("is above the max (168h)")
ErrSSHCheckPeriodNegative = errors.New("must be a positive duration")
ErrSSHCheckPeriodOnNonCheck = errors.New("checkPeriod is only valid with action \"check\"")
ErrInvalidLocalpart = errors.New("invalid localpart format, must be localpart:*@<domain>")
ErrSSHUsersMustBeSpecified = errors.New("users must be specified")
ErrSSHUserInvalid = errors.New("is not valid")
ErrSSHAcceptEnvEmpty = errors.New("acceptEnv values cannot be empty")
ErrSSHActionMustBeSpecified = errors.New("action must be specified")View on GitHub (pinned to 565fd254d0)
Solutions
- Remove autogroup:self from the offending position — check tagOwners and SSH destinations first
- In grants srcs it is fine; replace dst usages with autogroup:member, autogroup:tagged, or explicit users/tags
- Use 'headscale policy check' to get the exact location
Example fix
// before
"tagOwners": {"tag:app": ["autogroup:self"]}
// after
"tagOwners": {"tag:app": ["group:admins"]} Defensive patterns
Strategy: validation
Validate before calling
func autogroupSelfAllowedIn(position string) bool { return position == "grants.src" || position == "ssh.src" } Prevention
- Reserve autogroup:self for per-node-resolved positions (grant/SSH sources)
- Use autogroup:member/autogroup:tagged for dsts and owners
- Validate policy files in CI to catch misplaced autogroups
When it happens
Trigger: Using autogroup:self in a position resolved globally: as a tag owner, inside SSH destination resolution, in tests evaluation paths that need a flat IP set, or any Resolve() call without per-node context.
Common situations: Copy-pasting an autogroup from a grants src (valid) into tagOwners or an SSH dst (invalid); upgrading policies from examples that used * and reaching for autogroup:self as the replacement everywhere.
Related errors
- invalid action
- references undefined tag
- autogroup:self destination requires source to contain only u
- tags in SSH source cannot access autogroup:member (user-owne
- wildcard (*) is not supported as SSH destination
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/85c010dac20f42e5.
Report an issue: GitHub.