TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to update Primary node: the Cluster Secondary Catalog

Error message

Failed to update Primary node: the Cluster Secondary Catalog zone '{clusterCatalogDomain}' does not exists.

What it means

Thrown by UpdatePrimaryNodeAsync when GetAuthZoneInfo('cluster-catalog.<clusterDomain>') returns null. The update flow needs to rewrite the secondary catalog zone's primary name server addresses, so the zone must exist; its absence means cluster zone state is inconsistent or was deleted out-of-band.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:1586

                SaveConfigFile();
            }

            //validate for duplicate names
            foreach (KeyValuePair<int, ClusterNode> clusterNode in _clusterNodes)
            {
                if (clusterNode.Key == primaryNode.Id)
                    continue; //skip self

                if (clusterNode.Value.Name.Equals(primaryNodeUrl.Host, StringComparison.OrdinalIgnoreCase))
                    throw new DnsServerException("Failed to update Primary node: the Primary node's domain name already exists in the Cluster. Please try again after changing the Primary DNS Server's domain name.");
            }

            //get cluster secondary catalog zone
            string clusterCatalogDomain = "cluster-catalog." + _clusterDomain;

            AuthZoneInfo clusterSecondaryCatalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(clusterCatalogDomain);
            if (clusterSecondaryCatalogZoneInfo is null)
                throw new DnsServerException($"Failed to update Primary node: the Cluster Secondary Catalog zone '{clusterCatalogDomain}' does not exists.");

            //update primary node
            primaryNode.UpdateNode(primaryNodeUrl, primaryNodeIpAddresses);

            //update cluster catalog zone's primary name server
            clusterSecondaryCatalogZoneInfo.PrimaryNameServerAddresses = primaryNodeIpAddresses.Convert(delegate (IPAddress ipAddress) { return new NameServerAddress(primaryNodeUrl.Host, ipAddress); });

            //save all changes
            _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(clusterSecondaryCatalogZoneInfo.Name);
            SaveConfigFile();

            //trigger config and zone refresh
            TriggerRefreshForConfig(CONFIG_REFRESH_TIMER_INTERVAL);

            return primaryNode;
        }

        public void TriggerRefreshForConfig(IReadOnlyCollection<string> configRefreshIncludeZones = null)

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Re-create the cluster-catalog zone by rejoining the cluster (LeaveClusterAsync(true) then JoinClusterAsync) to rebuild consistent zone state.
  2. Restore the catalog zone from a known-good zone file backup.
  3. Confirm _clusterDomain is correct and the zone name spelling matches; recreate if a rename occurred.

Example fix

// before
await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, ips);

// after: verify zone presence, rebuild if missing
var catalog = "cluster-catalog." + clusterManager.ClusterDomain;
if (dnsServer.AuthZoneManager.GetAuthZoneInfo(catalog) is null)
{
    await clusterManager.LeaveClusterAsync(force: true);
    await clusterManager.JoinClusterAsync(primaryUrl, creds, ct);
}
await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, ips);
Defensive patterns

Strategy: validation

Validate before calling

string catalog = "cluster-catalog." + clusterManager.ClusterDomain;
if (dnsServer.AuthZoneManager.GetAuthZoneInfo(catalog) is null)
    throw new InvalidOperationException($"Missing catalog zone '{catalog}'; rebuild cluster state.");
await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, ips);

Type guard

static bool CatalogZoneExists(DnsWebService svc, string clusterDomain)
    => svc.DnsServer.AuthZoneManager.GetAuthZoneInfo("cluster-catalog." + clusterDomain) is not null;

Try / catch

try { await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, ips); }
catch (DnsServerException ex) when (ex.Message.Contains("Catalog zone") && ex.Message.Contains("does not exists"))
{
    await clusterManager.LeaveClusterAsync(force: true);
    await clusterManager.JoinClusterAsync(primaryUrl, creds, ct);
}

Prevention

When it happens

Trigger: UpdatePrimaryNodeAsync called when the 'cluster-catalog.<clusterDomain>' secondary catalog zone has been deleted, renamed, or never created on this node.

Common situations: Operator manually deleted the catalog zone; a prior failed promotion/join cleaned up zones partially; zone file corrupted on disk; the cluster domain changed but the catalog zone was not recreated.

Related errors


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