TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to promote to Primary node: the Cluster Secondary Cat

Error message

Failed to promote to Primary node: the Cluster Secondary Catalog zone does not exist.

What it means

Thrown by PromoteToPrimaryNodeAsync when GetAuthZoneInfo('cluster-catalog.<clusterDomain>') returns null. Promotion converts the existing SecondaryCatalog zone into a Catalog zone via ConvertZoneTypeTo, so the source catalog zone must exist; its absence means the cluster's zone state is inconsistent.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:1951

            if (saveConfig)
                SaveConfigFile();
        }

        public async Task PromoteToPrimaryNodeAsync(bool forceDeletePrimary)
        {
            if (!ClusterInitialized)
                throw new DnsServerException("Failed to promote to Primary node: the Cluster is not initialized.");

            //do validation
            ClusterNode selfNewPrimaryNode = GetSelfNode();
            if (selfNewPrimaryNode.Type != ClusterNodeType.Secondary)
                throw new DnsServerException("Failed to promote to Primary node: only Secondary nodes can be promoted to Primary nodes.");

            string clusterCatalogDomain = "cluster-catalog." + _clusterDomain;

            AuthZoneInfo clusterCatalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(clusterCatalogDomain);
            if (clusterCatalogZoneInfo is null)
                throw new DnsServerException("Failed to promote to Primary node: the Cluster Secondary Catalog zone does not exist.");

            AuthZoneInfo clusterZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(_clusterDomain);
            if (clusterZoneInfo is null)
                throw new DnsServerException("Failed to promote to Primary node: the Cluster Secondary zone does not exist.");

            //stop cluster config refresh timer
            StopConfigRefreshTimer();

            //resync config and delete current primary node from the cluster immediately
            ClusterNode existingPrimaryNode = GetPrimaryNode();

            if (!forceDeletePrimary)
            {
                //resync complete config from current primary node to ensure all data is synced
                _configLastSynced = DateTime.UnixEpoch; //to ensure complete config resync
                await existingPrimaryNode.SyncConfigAsync();

                //delete current cluster primary node

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Rebuild cluster zone state by leaving (force) and rejoining the cluster, which recreates the secondary catalog zone.
  2. Restore the catalog zone from backup if you have one.
  3. Verify _clusterDomain is correct so the constructed zone name matches what exists.

Example fix

// before
await clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);

// after: ensure the catalog zone exists before promoting
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.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);
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.");
await clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);

Type guard

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

Try / catch

try { await clusterManager.PromoteToPrimaryNodeAsync(false); }
catch (DnsServerException ex) when (ex.Message.Contains("Cluster Secondary Catalog zone does not exist"))
{
    await clusterManager.LeaveClusterAsync(force: true);
    await clusterManager.JoinClusterAsync(primaryUrl, creds, ct);
}

Prevention

When it happens

Trigger: Promoting a secondary whose 'cluster-catalog.<clusterDomain>' zone was deleted, renamed, or never created.

Common situations: Manual deletion of the catalog zone; a prior failed join/leave left zones half-cleaned; zone file corruption on disk; cluster domain changed without recreating the catalog zone.

Related errors


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