juanfont/headscale · error

autogroup:self destination requires source to contain only u

Error message

autogroup:self destination requires source to contain only users or groups, not tags or autogroup:tagged

What it means

SSH validation error (hscontrol/policy/v2/types.go:2186): autogroup:self is used as an SSH destination while the src contains tags or autogroup:tagged. autogroup:self dst means 'each user's own devices', which presupposes a user identity on the source side; tagged sources have no user identity to match.

Source

Thrown at hscontrol/policy/v2/types.go:44

// 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")
	ErrSSHActionInvalid                   = errors.New("is not a valid action")
	ErrSSHDestinationHostAlias            = errors.New("invalid dst")
	ErrTagNameMustStartWithLetter         = errors.New("tag names must start with a letter, after 'tag:'")
	ErrGroupMembersCannotBeRecursive      = errors.New("group members cannot be recursive")
)

// SSH check period constants per Tailscale docs:
// https://tailscale.com/docs/features/tailscale-ssh#checkperiod

View on GitHub (pinned to 565fd254d0)

Solutions

  1. Use only users and/or groups in src when dst includes autogroup:self
  2. For tagged bastions, target explicit tags or autogroup:tagged in dst instead
  3. Split the rule: one user-src rule with autogroup:self dst, one tag-src rule with tagged dsts

Example fix

// before
{"src": ["tag:bastion", "group:ops"], "dst": ["autogroup:self"], "users": ["root"], "action": "accept"}

// after (two rules)
{"src": ["group:ops"], "dst": ["autogroup:self"], "users": ["autogroup:nonroot"], "action": "check", "checkPeriod": "8h"}
{"src": ["tag:bastion"], "dst": ["tag:server"], "users": ["root"], "action": "accept"}
Defensive patterns

Strategy: validation

Validate before calling

func sshAutogroupSelfDstRuleValid(src []string) bool { return !slices.ContainsFunc(src, func(s string) bool { return strings.HasPrefix(s, "tag:") || s == "autogroup:tagged" }) }

Prevention

When it happens

Trigger: {"src": ["tag:bastion"], "dst": ["autogroup:self"], ...} — any tag/autogroup:tagged entry in src combined with autogroup:self in dst fails with this error.

Common situations: Building a bastion pattern with a tagged jump host that should SSH anywhere; converting older wildcard SSH rules to autogroup:self dst while keeping tagged sources.

Related errors


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