juanfont/headscale · error
%w: %q
Error message
%w: %q
What it means
Host.Validate rejected a hostname alias because it does not satisfy the hostname grammar checked by isHost() — typically characters outside the allowed set, a missing label, leading/trailing dots, or a value that is actually another alias form.
Source
Thrown at hscontrol/policy/v2/types.go:603
func (t *Tag) String() string {
return string(*t)
}
// MarshalJSON marshals the Tag to JSON.
func (t *Tag) MarshalJSON() ([]byte, error) {
return json.Marshal(string(*t))
}
// Host is a string that represents a hostname.
type Host string
func (h *Host) Validate() error {
if isHost(string(*h)) {
return nil
}
return fmt.Errorf("%w: %q", ErrInvalidHostname, *h)
}
func (h *Host) UnmarshalJSON(b []byte) error {
*h = Host(strings.Trim(string(b), `"`))
err := h.Validate()
if err != nil {
return err
}
return nil
}
func (h *Host) Resolve(p *Policy, _ types.Users, nodes views.Slice[types.NodeView]) (ResolvedAddresses, error) {
return newResolvedAddresses(h.resolve(p, nil, nodes))
}
func (h *Host) resolve(p *Policy, _ types.Users, _ views.Slice[types.NodeView]) (*netipx.IPSet, error) {View on GitHub (pinned to 565fd254d0)
Solutions
- Use a DNS-style name: lowercase letters, digits, hyphens, and dots, each label non-empty, e.g. 'web.example.com'.
- Remove spaces, underscores, and stray punctuation.
- If the value is meant to be a different alias type, use the right type (user email, tag:, group:).
Example fix
// before
"hosts": {"web server": "100.64.0.10/32"}
// after
"hosts": {"web-server": "100.64.0.10/32"} Defensive patterns
Strategy: validation
Validate before calling
var hostRe = regexp.MustCompile(`^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?)*$`)
func validHostname(s string) bool { return hostRe.MatchString(s) && len(s) <= 253 } Try / catch
if err := host.Validate(); err != nil {
if errors.Is(err, v2.ErrInvalidHostname) {
// strip spaces/underscores; use DNS-style label
}
return err
} Prevention
- Use DNS-label rules for hosts entries: no spaces or underscores.
- Run prettier/json lint plus a hosts-specific check on policy files.
- Prefer machine-generated hosts maps over hand-edited ones.
When it happens
Trigger: Hosts-map or destination values like 'web server' (space), '.web', 'web..example', or 'user@host' assigned to a Host field. isHost(string(h)) returns false in Host.Validate.
Common situations: Hand-editing the hosts section with display names containing spaces or underscores; pasting FQDNs with trailing dots; using an email or tag where a hostname was expected.
Related errors
- %w, got: %q
- %w: got %q, must be one of %v
- must be a positive duration
- checkPeriod is only valid with action "check"
- invalid localpart format, must be localpart:*@<domain>
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/a35ade2bc1790577.
Report an issue: GitHub.