{"record":{"id":"48f7494a77d0cb4d","repo":"juanfont/headscale","slug":"tag-not-found","errorCode":null,"errorMessage":"tag not found","messagePattern":"tag not found","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":127,"sourceCode":"\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\")\n\tErrAutogroupInternetSrc        = errors.New(\"autogroup:internet can only be used in ACL destinations\")\n\tErrAutogroupSelfSrc            = errors.New(\"\\\"autogroup:self\\\" not valid on the src side of a rule\")\n\tErrAutogroupNotSupportedACLSrc = errors.New(\"autogroup not supported for ACL sources\")\n\tErrAutogroupNotSupportedACLDst = errors.New(\"autogroup not supported for ACL destinations\")\n\tErrAutogroupDangerAllDst       = errors.New(\"cannot use autogroup:danger-all as a dst\")\n\tErrAutogroupNotSupportedSSHSrc = errors.New(\"autogroup not supported for SSH sources\")\n\tErrAutogroupNotSupportedSSHDst = errors.New(\"autogroup not supported for SSH destinations\")\n\tErrHostNotDefined              = errors.New(\"host not defined in policy\")\n\tErrSSHSourceAliasNotSupported  = errors.New(\"alias not supported for SSH source\")\n\tErrSSHDestAliasNotSupported    = errors.New(\"alias not supported for SSH destination\")\n\tErrUnknownField                = errors.New(\"unknown field\")","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L109-L145","documentation":"Returned by TagOwners.Contains (hscontrol/policy/v2/types.go:1488) and surfaced from Policy.validate when a tag: alias is used in a rule but has no corresponding entry in the policy's \"tagOwners\" map. Headscale (like Tailscale) requires every tag referenced in ACLs or SSH rules to be owned by at least one user or group, otherwise nodes cannot claim it.","triggerScenarios":"Policy with \"acls\": [{\"action\": \"accept\", \"src\": [\"tag:server\"], \"dst\": [...]}] but no \"tagOwners\": {\"tag:server\": [...]}. Also fires for tags used in SSH rules and (per the TODO at types.go:1997) will increasingly cover dst sides. Reported as \"src=tag not found: ...\" when raised from an ACL source check.","commonSituations":"Adding a new tag to ACLs and forgetting to grant ownership; renaming a tag in tagOwners but not in the rules; migrating from a policy style that pre-declared tags elsewhere. Nodes using the tag fail to register until fixed.","solutions":["Add a tagOwners entry granting an existing user/group ownership: \"tagOwners\": {\"tag:server\": [\"group:admin\"]}","Verify the tag name matches exactly (case-sensitive, must start with \"tag:\") in both tagOwners and the rule","If the tag is obsolete, remove its references from acls/ssh sections instead"],"exampleFix":"// before\n\"acls\": [{\"action\": \"accept\", \"src\": [\"tag:server\"], \"dst\": [\"*:*\"]}]\n\n// after\n\"tagOwners\": {\"tag:server\": [\"group:admin\"]},\n\"acls\": [{\"action\": \"accept\", \"src\": [\"tag:server\"], \"dst\": [\"*:*\"]}]","handlingStrategy":"validation","validationCode":"// Verify every tag referenced in rules has an owner before loading\nfunc tagsReferenced(p map[string]any) map[string]bool {\n\trefs := map[string]bool{}\n\tfor _, section := range []string{\"acls\", \"ssh\", \"tests\"} {\n\t\t// walk strings starting with \"tag:\" in src/dst arrays\n\t}\n\treturn refs\n}\n// then: every ref must be a key of tagOwners","typeGuard":"func isTagNotDefined(err error) bool {\n\treturn errors.Is(err, policy.ErrTagNotDefined)\n}","tryCatchPattern":"if err := p.Validate(); err != nil {\n\tif errors.Is(err, policy.ErrTagNotDefined) {\n\t\t// wrapped message contains the missing tag name\n\t\treturn fmt.Errorf(\"policy rejected, add tagOwners entry: %w\", err)\n\t}\n\treturn err\n}","preventionTips":["Declare tagOwners for every tag at the moment you first use the tag","Use a naming convention (tag:<service>:<role>) and grep policy files for tag: references before renaming","Keep policy under version control and diff tagOwners alongside acls in review"],"tags":["policy","tags","validation","acl","headscale"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}