{"record":{"id":"de621183a6491403","repo":"TechnitiumSoftware/DnsServer","slug":"failed-to-join-cluster-the-zone-primarynodeclus","errorCode":null,"errorMessage":"Failed to join Cluster: the zone '{primaryNodeClusterInfo.ClusterDomain}' already exists. Please delete the '{primaryNodeClusterInfo.ClusterDomain}' zone and try again.","messagePattern":"Failed to join Cluster: the zone '(.+?)' already exists\\. Please delete the '(.+?)' zone and try again\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Cluster/ClusterManager.cs","lineNumber":1379,"sourceCode":"                throw new TwoFactorAuthRequiredWebServiceException(\"Failed to join Cluster: two-factor authentication is required by the Primary node user account.\", ex);\n            }\n\n            try\n            {\n                //get cluster info\n                ClusterInfo primaryNodeClusterInfo = await primaryNodeApiClient.GetClusterStateAsync(cancellationToken: cancellationToken);\n\n                //do validations\n                if (!primaryNodeClusterInfo.ClusterInitialized)\n                    throw new DnsServerException(\"Failed to join Cluster: the Primary node does not have a Cluster initialized.\");\n\n                string clusterCatalogDomain = \"cluster-catalog.\" + primaryNodeClusterInfo.ClusterDomain;\n\n                if (_dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(clusterCatalogDomain) is not null)\n                    throw new DnsServerException($\"Failed to join Cluster: the zone '{clusterCatalogDomain}' already exists. Please delete the '{clusterCatalogDomain}' zone and try again.\");\n\n                if (_dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(primaryNodeClusterInfo.ClusterDomain) is not null)\n                    throw new DnsServerException($\"Failed to join Cluster: the zone '{primaryNodeClusterInfo.ClusterDomain}' already exists. Please delete the '{primaryNodeClusterInfo.ClusterDomain}' zone and try again.\");\n\n                //create self node\n                string serverDomain = _dnsWebService.DnsServer.ServerDomain;\n                if (!serverDomain.EndsWith(\".\" + primaryNodeClusterInfo.ClusterDomain, StringComparison.OrdinalIgnoreCase))\n                {\n                    int x = serverDomain.IndexOf('.');\n                    if (x < 0)\n                        serverDomain = serverDomain + \".\" + primaryNodeClusterInfo.ClusterDomain;\n                    else\n                        serverDomain = string.Concat(serverDomain.AsSpan(0, x), \".\", primaryNodeClusterInfo.ClusterDomain);\n                }\n\n                Uri secondaryNodeUrl = new Uri($\"https://{serverDomain}:{_dnsWebService.WebServiceTlsPort}/\");\n\n                ClusterNode selfSecondaryNode = new ClusterNode(this, RandomNumberGenerator.GetInt32(int.MaxValue), secondaryNodeUrl, secondaryNodeIpAddresses, ClusterNodeType.Secondary, ClusterNodeState.Self);\n\n                //join cluster\n                primaryNodeClusterInfo = await primaryNodeApiClient.JoinClusterAsync(selfSecondaryNode.Id, secondaryNodeUrl, secondaryNodeIpAddresses, _dnsWebService.WebServiceTlsCertificate, cancellationToken);","sourceCodeStart":1361,"sourceCodeEnd":1397,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Cluster/ClusterManager.cs#L1361-L1397","documentation":"Before joining, the Secondary finds a local zone matching the cluster domain itself ('<clusterDomain>') already exists. The join would manage this zone, so a pre-existing one (prior cluster, manual import) blocks it.","triggerScenarios":"Re-joining after a partial join; a zone for the cluster domain created manually or via import; a leftover from a previous cluster with the same domain.","commonSituations":"Restore from backup; aborted join cleanup; an operator pre-created the domain zone.","solutions":["Delete the existing '<clusterDomain>' zone, then retry join","Fully reset previous cluster state to remove stale zones","Confirm no conflicting zone exists before join"],"exampleFix":"// before\nawait clusterManager.InitializeAndJoinClusterAsync(ips, primaryUrl, user, pass);\n\n// after\nif (dnsServer.AuthZoneManager.GetAuthZoneInfo(info.ClusterDomain) is not null)\n    dnsServer.AuthZoneManager.DeleteZone(info.ClusterDomain);\nawait clusterManager.InitializeAndJoinClusterAsync(ips, primaryUrl, user, pass);","handlingStrategy":"validation","validationCode":"if (dnsServer.AuthZoneManager.GetAuthZoneInfo(info.ClusterDomain) is not null)\n    return Conflict($\"Zone '{info.ClusterDomain}' exists; delete it before joining.\");\nawait clusterManager.InitializeAndJoinClusterAsync(ips, primaryUrl, user, pass);","typeGuard":null,"tryCatchPattern":"catch (DnsServerException ex) when (ex.Message.Contains(info.ClusterDomain) && ex.Message.Contains(\"already exists\"))\n{ /* offer to delete the conflicting cluster-domain zone then retry */ }","preventionTips":["Remove cluster-domain zones before re-joining","Run a pre-join check for catalog and cluster-domain zones"],"tags":["cluster","zones","lifecycle","join","validation","dns-server"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}