{"record":{"id":"45a93618e6f4145e","repo":"juanfont/headscale","slug":"invalid-autogroup","errorCode":null,"errorMessage":"invalid autogroup","messagePattern":"invalid autogroup","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":116,"sourceCode":"// caps are accepted by Tailscale SaaS, but delivering them via headscale\n// without the matching server-side machinery would be misleading — nodes\n// would advertise a feature that does not work. Reject at policy load and\n// point operators at the issue.\nvar nodeAttrUnsupportedCaps = map[tailcfg.NodeCapability]string{\n\ttailcfg.NodeAttrFunnel: \"https://github.com/juanfont/headscale/issues/2527\",\n}\n\n// Policy validation errors.\nvar (\n\tErrInvalidUsername             = errors.New(\"username must contain @\")\n\tErrUserNotFound                = errors.New(\"user not found\")\n\tErrMultipleUsersFound          = errors.New(\"multiple users found\")\n\tErrInvalidGroupFormat          = errors.New(\"group must start with 'group:'\")\n\tErrInvalidTagFormat            = errors.New(\"tag must start with 'tag:'\")\n\tErrInvalidHostname             = errors.New(\"invalid hostname\")\n\tErrHostResolve                 = errors.New(\"error resolving host\")\n\tErrInvalidPrefix               = errors.New(\"invalid prefix\")\n\tErrInvalidAutogroup            = errors.New(\"invalid autogroup\")\n\tErrUnknownAutogroup            = errors.New(\"unknown autogroup\")\n\tErrHostportMissingColon        = errors.New(\"hostport must contain a colon\")\n\tErrTypeNotSupported            = errors.New(\"type not supported\")\n\tErrInvalidAlias                = errors.New(\"invalid alias format\")\n\tErrInvalidAutoApprover         = errors.New(\"invalid auto approver format\")\n\tErrInvalidOwner                = errors.New(\"invalid owner format\")\n\tErrGroupNotDefined             = errors.New(\"group not defined in policy\")\n\tErrInvalidGroupMember          = errors.New(\"invalid group member type\")\n\tErrGroupValueNotArray          = errors.New(\"group value must be an array of users\")\n\tErrInvalidHostIP               = errors.New(\"hostname contains invalid IP address\")\n\tErrTagNotDefined               = errors.New(\"tag not found\")\n\tErrAutoApproverNotAlias        = errors.New(\"auto approver is not an alias\")\n\tErrInvalidACLAction            = errors.New(\"invalid ACL action\")\n\tErrInvalidSSHAction            = errors.New(\"invalid SSH action\")\n\tErrInvalidProtocolNumber       = errors.New(\"invalid protocol number\")\n\tErrProtocolLeadingZero         = errors.New(\"leading 0 not permitted in protocol number\")\n\tErrProtocolOutOfRange          = errors.New(\"protocol number out of range (0-255)\")\n\tErrAutogroupNotSupported       = errors.New(\"autogroup not supported in headscale\")","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L98-L134","documentation":"AutoGroup parsing (hscontrol/policy/v2/types.go:748) accepts only autogroups in headscale's allowed set (the valid list is embedded in the error). A token starting with 'autogroup:' whose suffix is not in that set — e.g. autogroup:admin, autogroup:owner — fails at UnmarshalJSON with this sentinel, so the policy never reaches per-position validators.","triggerScenarios":"Writing 'autogroup:admin' or 'autogroup:owner' anywhere in a policy (these exist in other Tailscale-flavoured grammars but not headscale's); any misspelled autogroup like 'autogroup:members'. Fails at parse time.","commonSituations":"Copying ACLs written for another control plane that supports admin/owner autogroups; assuming the Tailscale SaaS autogroup list applies verbatim to headscale.","solutions":["Use only the autogroups listed in the error message (self, member, tagged, internet, danger-all)","Replace autogroup:admin/owner with an explicit group of admin users","Consult headscale's ACL docs for the supported autogroup set"],"exampleFix":"// before\n{\"acls\": [{\"action\": \"accept\", \"src\": [\"autogroup:admin\"], \"dst\": [\"*:*\"]}]}\n// after\n{\"acls\": [{\"action\": \"accept\", \"src\": [\"group:admins\"], \"dst\": [\"*:*\"]}]}","handlingStrategy":"validation","validationCode":"valid := map[string]bool{\"autogroup:self\": true, \"autogroup:member\": true, \"autogroup:tagged\": true, \"autogroup:internet\": true, \"autogroup:danger-all\": true}\nif strings.HasPrefix(tok, \"autogroup:\") && !valid[tok] {\n    return fmt.Errorf(\"unknown autogroup %q\", tok)\n}","typeGuard":"func isValidAutogroup(s string) bool { return validAutogroups[s] }","tryCatchPattern":"if errors.Is(err, policy.ErrInvalidAutogroup) {\n    // error message lists valid values; pick from it\n}","preventionTips":["Use only headscale-documented autogroups","Do not copy SaaS-only autogroups like autogroup:admin"],"tags":["headscale","policy","autogroup","acl","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}