{"record":{"id":"0d3756c096af6e91","repo":"TechnitiumSoftware/DnsServer","slug":"failed-to-join-cluster-the-primary-node-url-must","errorCode":null,"errorMessage":"Failed to join Cluster: the Primary Node URL must use the domain name of the Primary node and not its IP address.","messagePattern":"Failed to join Cluster: the Primary Node URL must use the domain name of the Primary node and not its IP address\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Cluster/ClusterManager.cs","lineNumber":1334,"sourceCode":"            {\n                _notifyAllSecondaryNodesTimerTriggered = false;\n            }\n        }\n\n        #endregion\n\n        #region secondary node\n\n        public async Task InitializeAndJoinClusterAsync(IReadOnlyList<IPAddress> secondaryNodeIpAddresses, Uri primaryNodeUrl, string primaryNodeUsername, string primaryNodePassword, string primaryNodeTotp = null, IReadOnlyList<IPAddress> primaryNodeIpAddresses = null, bool ignoreCertificateErrors = false, CancellationToken cancellationToken = default)\n        {\n            if (ClusterInitialized)\n                throw new DnsServerException(\"Failed to join Cluster: the Cluster is already initialized.\");\n\n            if (!_dnsWebService.IsWebServiceTlsEnabled)\n                throw new InvalidOperationException();\n\n            if (IPAddress.TryParse(primaryNodeUrl.Host, out _))\n                throw new DnsServerException(\"Failed to join Cluster: the Primary Node URL must use the domain name of the Primary node and not its IP address.\");\n\n            if (primaryNodeIpAddresses is null)\n            {\n                try\n                {\n                    IReadOnlyList<IPAddress> ipAddresses = await DnsClient.ResolveIPAsync(_dnsWebService.DnsServer, primaryNodeUrl.Host, _dnsWebService.DnsServer.IPv6Mode, cancellationToken);\n                    if (ipAddresses.Count < 1)\n                        throw new DnsServerException($\"Failed to join Cluster: the domain name '{primaryNodeUrl.Host}' does not have an A/AAAA record configured.\");\n\n                    primaryNodeIpAddresses = ipAddresses;\n                }\n                catch (Exception ex)\n                {\n                    throw new DnsServerException($\"Failed to join Cluster: the Primary node domain name '{primaryNodeUrl.Host}' could not be resolved to an IP address. Please specify the Primary node IP address manually.\", ex);\n                }\n            }\n\n            //login to primary node API","sourceCodeStart":1316,"sourceCodeEnd":1352,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Cluster/ClusterManager.cs#L1316-L1352","documentation":"InitializeAndJoinClusterAsync requires the Primary node URL to use a hostname, not an IP literal. IPAddress.TryParse(primaryNodeUrl.Host) succeeding means an IP was supplied; the cluster keys members by domain name and needs a resolvable host for certificates and DNS.","triggerScenarios":"Passing primaryNodeUrl = new Uri(\"https://10.0.0.5:5380\") instead of a hostname; supplying the Primary's IP in the URL while providing IPs separately.","commonSituations":"Quick lab setups using IPs; copy-paste from a connection string; no DNS name configured for the Primary.","solutions":["Use the Primary's domain name in the URL (e.g. https://dns-primary.example.com:5380)","Configure a DNS A/AAAA record for the Primary if none exists","If only an IP is available, set up a hostname (hosts/DNS) first"],"exampleFix":"// before\nvar primaryUrl = new Uri(\"https://10.0.0.5:5380\");\nawait clusterManager.InitializeAndJoinClusterAsync(ips, primaryUrl, user, pass);\n\n// after\nvar primaryUrl = new Uri(\"https://dns-primary.example.com:5380\");\nawait clusterManager.InitializeAndJoinClusterAsync(\n    ips, primaryUrl, user, pass,\n    primaryNodeIpAddresses: new[] { IPAddress.Parse(\"10.0.0.5\") });","handlingStrategy":"validation","validationCode":"if (IPAddress.TryParse(primaryNodeUrl.Host, out _))\n    return BadRequest(\"Primary URL must use a domain name, not an IP.\");\nawait clusterManager.InitializeAndJoinClusterAsync(ips, primaryUrl, user, pass);","typeGuard":null,"tryCatchPattern":"catch (DnsServerException ex) when (ex.Message.Contains(\"must use the domain name\"))\n{ /* prompt for a hostname-based URL */ }","preventionTips":["Always address the Primary by FQDN","Provide IPs via primaryNodeIpAddresses, never in the URL host"],"tags":["cluster","dns-names","validation","join","dns-server"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}