juanfont/headscale · error
%q is not a valid DNS label: %w
Error message
%q is not a valid DNS label: %w
What it means
Returned by types.ValidateGivenName when the candidate name fails dnsname.ValidLabel — i.e. it is not a legal DNS label (empty, >63 chars, illegal characters, leading/trailing hyphen). Admin write paths such as node rename call this first because the mapper cannot build a map for a node whose FQDN cannot be formed.
Source
Thrown at hscontrol/types/node.go:529
return "", fmt.Errorf(
"creating valid FQDN (%s): %w",
hostname,
ErrHostnameTooLong,
)
}
return hostname, nil
}
// ValidateGivenName reports whether givenName is usable as a node's DNS label:
// a valid DNS label that, combined with baseDomain, yields an FQDN within
// MaxHostnameLength. Admin-facing write paths (e.g. node rename) reject names
// that fail this, since the mapper cannot build a map for a node — or any of
// its peers — whose GetFQDN fails. Derived paths sanitise/coerce instead.
func ValidateGivenName(givenName, baseDomain string) error {
err := dnsname.ValidLabel(givenName)
if err != nil {
return fmt.Errorf("%q is not a valid DNS label: %w", givenName, err)
}
// Reuse GetFQDN so the length bound stays identical to what the mapper
// enforces; a valid 63-char label can still overflow under a long
// base_domain.
_, err = (&Node{GivenName: givenName}).GetFQDN(baseDomain)
if err != nil {
return err
}
return nil
}
// AnnouncedRoutes returns the list of routes the node announces, as
// reported by the client in [tailcfg.Hostinfo.RoutableIPs]. Announcement alone
// does not grant visibility — see [Node.SubnetRoutes] for approval-gated
// access.
func (node *Node) AnnouncedRoutes() []netip.Prefix {View on GitHub (pinned to 565fd254d0)
Solutions
- Use a strict DNS label: 1-63 chars, letters/digits/hyphens only, no leading or trailing hyphen
- Sanitize free-text names before rename: lowercase, replace separators with hyphens, trim hyphens, cap at 63 chars
- Run ValidateGivenName in your tooling before submitting the rename so the error surfaces early with context
Example fix
// before name := "file server (2)" err := types.ValidateGivenName(name, baseDomain) // not a valid DNS label // after name := "file-server-2" err := types.ValidateGivenName(name, baseDomain)
Defensive patterns
Strategy: validation
Validate before calling
import (
"regexp"
"headscale/hscontrol/types"
)
var dnsLabel = regexp.MustCompile(`^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?$`)
func safeGivenName(raw string) (string, error) {
if !dnsLabel.MatchString(raw) {
return "", fmt.Errorf("%q is not DNS-label safe", raw)
}
if err := types.ValidateGivenName(raw, baseDomain); err != nil {
return "", err
}
return raw, nil
} Try / catch
if err := types.ValidateGivenName(name, baseDomain); err != nil {
// derive a sanitized fallback instead of persisting the bad name
name = sanitizeToDNSLabel(name)
} Prevention
- Generate node names from an allowlist pattern (alnum + hyphen) in automation
- Trim and lowercase user-supplied names before validation
- Surface validation errors in rename UIs before submission
When it happens
Trigger: Calling ValidateGivenName with names like "my machine" (space), "-lead", "trail-", "a"*64, "under_score", or "" — used in rename handlers and provisioning code before persisting a GivenName.
Common situations: Users renaming nodes via the CLI/API with hostnames containing spaces, underscores, or other non-DNS characters; automation scripts deriving node names from free-text asset labels.
Related errors
- given name already in use by another node
- ErrHostnameTooLong
- node name is not unique
- hostname contains invalid IP address
- username must be at least 2 characters long
AI-assisted analysis of juanfont/headscale@565fd254d0 (2026-08-15).
Data as JSON: /api/errors/1cf2e60ee126e7fd.
Report an issue: GitHub.