{"record":{"id":"ac42129060e52584","repo":"juanfont/headscale","slug":"error-resolving-host","errorCode":null,"errorMessage":"error resolving host","messagePattern":"error resolving host","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":114,"sourceCode":"// nodeAttrUnsupportedCaps lists caps that headscale parses but cannot act on\n// today. Each entry maps to the tracking issue an operator can follow. The\n// 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\")","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L96-L132","documentation":"Host.resolve (hscontrol/policy/v2/types.go:621-630) looks the hostname up in the policy's own hosts map (p.Hosts) — headscale does NOT do DNS resolution for ACL aliases. If the name has no entry, this sentinel wrapped with the name is returned and policy compilation fails.","triggerScenarios":"An ACL references 'example-host:443' but the policy has no {\"hosts\": {\"example-host\": \"10.0.0.5/32\"}} entry. Triggered at compile time via Host.Resolve, e.g. during 'headscale policy set' or server reload with the policy active.","commonSituations":"Assuming headscale resolves public DNS names in ACLs (Tailscale SaaS-style behaviour); hosts entry renamed or removed while ACLs still reference it; typo between hosts key and ACL reference.","solutions":["Add the host to the policy's hosts map with its IP/CIDR","Or replace the hostname token with the literal IP prefix in the ACL","Keep hosts keys and ACL references in sync — grep the policy for the name"],"exampleFix":"// before\n{\"acls\": [{\"action\": \"accept\", \"src\": [\"group:admins\"], \"dst\": [\"example-host:443\"]}]}\n// after\n{\"hosts\": {\"example-host\": \"10.0.0.5/32\"}, \"acls\": [{\"action\": \"accept\", \"src\": [\"group:admins\"], \"dst\": [\"example-host:443\"]}]}","handlingStrategy":"validation","validationCode":"// every host referenced in rules must exist in hosts map\nfor _, name := range referencedHosts(policy) {\n    if _, ok := policy.Hosts[name]; !ok {\n        return fmt.Errorf(\"host %q not defined in hosts map\", name)\n    }\n}","typeGuard":"func hostDefined(hosts map[string]string, name string) bool { _, ok := hosts[name]; return ok }","tryCatchPattern":"if errors.Is(err, policy.ErrHostResolve) {\n    // add a hosts entry or replace with literal IP prefix\n}","preventionTips":["Never assume DNS resolution for ACL hostnames in headscale","Keep hosts map and ACL references in the same review","Grep for removed host names before deleting entries"],"tags":["headscale","policy","hosts","acl","dns"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}