{"record":{"id":"c8bf2d50160ec3a4","repo":"juanfont/headscale","slug":"w-hostname-q-address-q","errorCode":null,"errorMessage":"%w: hostname %q address %q","messagePattern":"%w: hostname %q address %q","errorType":"validation","errorClass":"ErrInvalidHostIP","httpStatus":null,"severity":"error","filePath":"hscontrol/policy/v2/types.go","lineNumber":1426,"sourceCode":"\tif err != nil {\n\t\treturn err\n\t}\n\n\t*h = make(Hosts)\n\n\tfor key, value := range rawHosts {\n\t\thost := Host(key)\n\n\t\terr := host.Validate()\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tvar prefix Prefix\n\n\t\terr = prefix.parseString(value)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"%w: hostname %q address %q\", ErrInvalidHostIP, key, value)\n\t\t}\n\n\t\t(*h)[host] = prefix\n\t}\n\n\treturn nil\n}\n\n// MarshalJSON marshals the Hosts to JSON.\nfunc (h *Hosts) MarshalJSON() ([]byte, error) {\n\tif *h == nil {\n\t\treturn []byte(\"{}\"), nil\n\t}\n\n\trawHosts := make(map[string]string)\n\tfor host, prefix := range *h {\n\t\trawHosts[string(host)] = prefix.String()\n\t}","sourceCodeStart":1408,"sourceCodeEnd":1444,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/policy/v2/types.go#L1408-L1444","documentation":"During Hosts.UnmarshalJSON, the host name passed Validate but its address value failed prefix.parseString, so it cannot be interpreted as an IP or CIDR prefix (ErrInvalidHostIP). Hostname and address are both included.","triggerScenarios":"A hosts entry like \"example-host\": \"not-an-ip\", a bare word, or a malformed CIDR such as \"10.0.0/24\". DNS names are also rejected here: the value must be an address.","commonSituations":"Expecting hosts to alias DNS names instead of IPs; typos in octets or prefix lengths; using an IPv6 address with bad compression syntax.","solutions":["Set the value to a valid IP (\"10.0.0.5\") or CIDR prefix (\"10.0.0.0/24\")","Use MagicDNS / node names instead of hosts if you wanted DNS-style aliasing","Check for stray characters or missing netmask digits"],"exampleFix":"// before\n\"hosts\": {\"myserver\": \"myserver.example.com\"}\n// after\n\"hosts\": {\"myserver\": \"100.64.0.5\"}","handlingStrategy":"validation","validationCode":"func validHostAddress(s string) bool {\n\tif ip, err := netip.ParseAddr(s); err == nil { _ = ip; return true }\n\t_, err := netip.ParsePrefix(s)\n\treturn err == nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["hosts maps names to IPs/prefixes, not DNS names — use MagicDNS for name aliasing","Validate addresses with netip.ParseAddr/ParsePrefix in policy generators"],"tags":["policy","hosts","ip","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}