TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to join Cluster: the zone '{clusterCatalogDomain}' al

Error message

Failed to join Cluster: the zone '{clusterCatalogDomain}' already exists. Please delete the '{clusterCatalogDomain}' zone and try again.

What it means

Before joining, the Secondary checks its local zones and finds 'cluster-catalog.<clusterDomain>' already exists. Joining would create this catalog zone, so a pre-existing one (from a prior or aborted join) blocks the operation.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:1376

            }
            catch (TwoFactorAuthRequiredHttpApiClientException ex)
            {
                throw new TwoFactorAuthRequiredWebServiceException("Failed to join Cluster: two-factor authentication is required by the Primary node user account.", ex);
            }

            try
            {
                //get cluster info
                ClusterInfo primaryNodeClusterInfo = await primaryNodeApiClient.GetClusterStateAsync(cancellationToken: cancellationToken);

                //do validations
                if (!primaryNodeClusterInfo.ClusterInitialized)
                    throw new DnsServerException("Failed to join Cluster: the Primary node does not have a Cluster initialized.");

                string clusterCatalogDomain = "cluster-catalog." + primaryNodeClusterInfo.ClusterDomain;

                if (_dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(clusterCatalogDomain) is not null)
                    throw new DnsServerException($"Failed to join Cluster: the zone '{clusterCatalogDomain}' already exists. Please delete the '{clusterCatalogDomain}' zone and try again.");

                if (_dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(primaryNodeClusterInfo.ClusterDomain) is not null)
                    throw new DnsServerException($"Failed to join Cluster: the zone '{primaryNodeClusterInfo.ClusterDomain}' already exists. Please delete the '{primaryNodeClusterInfo.ClusterDomain}' zone and try again.");

                //create self node
                string serverDomain = _dnsWebService.DnsServer.ServerDomain;
                if (!serverDomain.EndsWith("." + primaryNodeClusterInfo.ClusterDomain, StringComparison.OrdinalIgnoreCase))
                {
                    int x = serverDomain.IndexOf('.');
                    if (x < 0)
                        serverDomain = serverDomain + "." + primaryNodeClusterInfo.ClusterDomain;
                    else
                        serverDomain = string.Concat(serverDomain.AsSpan(0, x), ".", primaryNodeClusterInfo.ClusterDomain);
                }

                Uri secondaryNodeUrl = new Uri($"https://{serverDomain}:{_dnsWebService.WebServiceTlsPort}/");

                ClusterNode selfSecondaryNode = new ClusterNode(this, RandomNumberGenerator.GetInt32(int.MaxValue), secondaryNodeUrl, secondaryNodeIpAddresses, ClusterNodeType.Secondary, ClusterNodeState.Self);

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Delete the existing 'cluster-catalog.<clusterDomain>' zone, then retry join
  2. Fully leave/reset the previous cluster to clean up catalog zones
  3. Verify no stale catalog zones remain before join

Example fix

// before
await clusterManager.InitializeAndJoinClusterAsync(ips, primaryUrl, user, pass);

// after
var catalog = "cluster-catalog." + info.ClusterDomain;
if (dnsServer.AuthZoneManager.GetAuthZoneInfo(catalog) is not null)
    dnsServer.AuthZoneManager.DeleteZone(catalog);
await clusterManager.InitializeAndJoinClusterAsync(ips, primaryUrl, user, pass);
Defensive patterns

Strategy: validation

Validate before calling

string catalog = "cluster-catalog." + info.ClusterDomain;
if (dnsServer.AuthZoneManager.GetAuthZoneInfo(catalog) is not null)
    return Conflict($"Zone '{catalog}' exists; delete it before joining.");
await clusterManager.InitializeAndJoinClusterAsync(ips, primaryUrl, user, pass);

Try / catch

catch (DnsServerException ex) when (ex.Message.Contains("cluster-catalog") && ex.Message.Contains("already exists"))
{ /* offer to delete the stale catalog zone then retry */ }

Prevention

When it happens

Trigger: Re-joining after a failed or partial join left the catalog zone behind; importing a config that already had the catalog zone; a leftover zone from a different cluster.

Common situations: Retry of join after a crash; restoring from backup that included cluster zones; partial cleanup after leaving a cluster.

Related errors


AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13). Data as JSON: /api/errors/fb1ad2d43421d509. Report an issue: GitHub.