{"record":{"id":"3c752738f2ce0017","repo":"juanfont/headscale","slug":"errhostnametoolong","errorCode":"ErrHostnameTooLong","errorMessage":"creating valid FQDN (%s): %w","messagePattern":"creating valid FQDN \\((.+?)\\): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"hscontrol/types/node.go","lineNumber":511,"sourceCode":"}\n\nfunc (node *Node) GetFQDN(baseDomain string) (string, error) {\n\tif node.GivenName == \"\" {\n\t\treturn \"\", fmt.Errorf(\"creating valid FQDN: %w\", ErrNodeHasNoGivenName)\n\t}\n\n\thostname := node.GivenName\n\n\tif baseDomain != \"\" {\n\t\thostname = fmt.Sprintf(\n\t\t\t\"%s.%s.\",\n\t\t\tnode.GivenName,\n\t\t\tbaseDomain,\n\t\t)\n\t}\n\n\tif len(hostname) > MaxHostnameLength {\n\t\treturn \"\", fmt.Errorf(\n\t\t\t\"creating valid FQDN (%s): %w\",\n\t\t\thostname,\n\t\t\tErrHostnameTooLong,\n\t\t)\n\t}\n\n\treturn hostname, nil\n}\n\n// ValidateGivenName reports whether givenName is usable as a node's DNS label:\n// a valid DNS label that, combined with baseDomain, yields an FQDN within\n// MaxHostnameLength. Admin-facing write paths (e.g. node rename) reject names\n// that fail this, since the mapper cannot build a map for a node — or any of\n// its peers — whose GetFQDN fails. Derived paths sanitise/coerce instead.\nfunc ValidateGivenName(givenName, baseDomain string) error {\n\terr := dnsname.ValidLabel(givenName)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"%q is not a valid DNS label: %w\", givenName, err)","sourceCodeStart":493,"sourceCodeEnd":529,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/types/node.go#L493-L529","documentation":"Returned by Node.GetFQDN when combining the node's GivenName with base_domain (plus trailing dot) exceeds MaxHostnameLength (255 ASCII chars). It wraps ErrHostnameTooLong. The mapper needs a valid FQDN to build the MapResponse, so an over-long name is a hard failure, not a truncation.","triggerScenarios":"A node registers (or is renamed to) a long GivenName while dns.base_domain is long enough that given + '.' + base + '.' exceeds 255 characters. GetFQDN(baseDomain) is called from the mapper and from ValidateGivenName.","commonSituations":"Machines with long hostnames joining a tailnet with a long MagicDNS base_domain; admin rename operations that pass a very long name; DNS label is valid (≤63 chars) but the FQDN overflows under the base domain.","solutions":["Shorten the node's given name (hostname) before registering or renaming it","Shorten dns.base_domain in the headscale config","Validate prospective names with types.ValidateGivenName before applying them in admin tooling"],"exampleFix":"// before\nbaseDomain := \"very-long-example-subdomain.tailnet.example-corporation.internal.\"\nnode := &Node{GivenName: \"machine-with-a-very-long-hostname\"}\nfqdn, err := node.GetFQDN(baseDomain) // ErrHostnameTooLong\n// after\nbaseDomain := \"tailnet.example.com\"\nnode := &Node{GivenName: \"build01\"}\nfqdn, err := node.GetFQDN(baseDomain)","handlingStrategy":"validation","validationCode":"import \"headscale/hscontrol/types\"\n\n// call before renaming or pre-registering a node\nif err := types.ValidateGivenName(newName, cfg.TailcfgDNS.BaseDomain); err != nil {\n    return err // includes hostname-too-long via GetFQDN reuse\n}","typeGuard":null,"tryCatchPattern":"fqdn, err := node.GetFQDN(baseDomain)\nif err != nil {\n    if errors.Is(err, types.ErrHostnameTooLong) {\n        // shorten name or base domain, then retry\n    }\n    return err\n}","preventionTips":["Keep given names short (machine role + number) regardless of the 63-char label cap","Prefer a short dns.base_domain so headroom exists for long hostnames","Validate names with ValidateGivenName in admin tooling before they reach the mapper"],"tags":["dns","node","magicdns","validation"],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}