{"record":{"id":"8fb8a04fdd421562","repo":"TechnitiumSoftware/DnsServer","slug":"failed-to-promote-to-primary-node-the-cluster-sec","errorCode":null,"errorMessage":"Failed to promote to Primary node: the Cluster Secondary Catalog zone does not exist.","messagePattern":"Failed to promote to Primary node: the Cluster Secondary Catalog zone does not exist\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Cluster/ClusterManager.cs","lineNumber":1951,"sourceCode":"            if (saveConfig)\n                SaveConfigFile();\n        }\n\n        public async Task PromoteToPrimaryNodeAsync(bool forceDeletePrimary)\n        {\n            if (!ClusterInitialized)\n                throw new DnsServerException(\"Failed to promote to Primary node: the Cluster is not initialized.\");\n\n            //do validation\n            ClusterNode selfNewPrimaryNode = GetSelfNode();\n            if (selfNewPrimaryNode.Type != ClusterNodeType.Secondary)\n                throw new DnsServerException(\"Failed to promote to Primary node: only Secondary nodes can be promoted to Primary nodes.\");\n\n            string clusterCatalogDomain = \"cluster-catalog.\" + _clusterDomain;\n\n            AuthZoneInfo clusterCatalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(clusterCatalogDomain);\n            if (clusterCatalogZoneInfo is null)\n                throw new DnsServerException(\"Failed to promote to Primary node: the Cluster Secondary Catalog zone does not exist.\");\n\n            AuthZoneInfo clusterZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(_clusterDomain);\n            if (clusterZoneInfo is null)\n                throw new DnsServerException(\"Failed to promote to Primary node: the Cluster Secondary zone does not exist.\");\n\n            //stop cluster config refresh timer\n            StopConfigRefreshTimer();\n\n            //resync config and delete current primary node from the cluster immediately\n            ClusterNode existingPrimaryNode = GetPrimaryNode();\n\n            if (!forceDeletePrimary)\n            {\n                //resync complete config from current primary node to ensure all data is synced\n                _configLastSynced = DateTime.UnixEpoch; //to ensure complete config resync\n                await existingPrimaryNode.SyncConfigAsync();\n\n                //delete current cluster primary node","sourceCodeStart":1933,"sourceCodeEnd":1969,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Cluster/ClusterManager.cs#L1933-L1969","documentation":"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.","triggerScenarios":"Promoting a secondary whose 'cluster-catalog.<clusterDomain>' zone was deleted, renamed, or never created.","commonSituations":"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.","solutions":["Rebuild cluster zone state by leaving (force) and rejoining the cluster, which recreates the secondary catalog zone.","Restore the catalog zone from backup if you have one.","Verify _clusterDomain is correct so the constructed zone name matches what exists."],"exampleFix":"// before\nawait clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);\n\n// after: ensure the catalog zone exists before promoting\nvar catalog = \"cluster-catalog.\" + clusterManager.ClusterDomain;\nif (dnsServer.AuthZoneManager.GetAuthZoneInfo(catalog) is null)\n{\n    await clusterManager.LeaveClusterAsync(force: true);\n    await clusterManager.JoinClusterAsync(primaryUrl, creds, ct);\n}\nawait clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);","handlingStrategy":"validation","validationCode":"string catalog = \"cluster-catalog.\" + clusterManager.ClusterDomain;\nif (dnsServer.AuthZoneManager.GetAuthZoneInfo(catalog) is null)\n    throw new InvalidOperationException($\"Missing catalog zone '{catalog}'; rebuild cluster.\");\nawait clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);","typeGuard":"static bool PromoteCatalogZoneExists(DnsWebService svc, string clusterDomain)\n    => svc.DnsServer.AuthZoneManager.GetAuthZoneInfo(\"cluster-catalog.\" + clusterDomain) is not null;","tryCatchPattern":"try { await clusterManager.PromoteToPrimaryNodeAsync(false); }\ncatch (DnsServerException ex) when (ex.Message.Contains(\"Cluster Secondary Catalog zone does not exist\"))\n{\n    await clusterManager.LeaveClusterAsync(force: true);\n    await clusterManager.JoinClusterAsync(primaryUrl, creds, ct);\n}","preventionTips":["Never delete the cluster-catalog zone manually on a clustered node.","Verify both cluster zones exist before promoting.","Back up zone files so a missing zone can be restored."],"tags":["cluster","dns-zone","promote","missing-state","technitium"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}