{"record":{"id":"da0fc9909a89cfaf","repo":"TechnitiumSoftware/DnsServer","slug":"failed-to-promote-to-primary-node-the-cluster-pri","errorCode":null,"errorMessage":"Failed to promote to Primary node: the Cluster Primary zone does not exist.","messagePattern":"Failed to promote to Primary node: the Cluster Primary zone does not exist\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"critical","filePath":"DnsServerCore/Cluster/ClusterManager.cs","lineNumber":2001,"sourceCode":"                    continue;\n\n                updatedClusterNodes[existingClusterNode.Key] = existingClusterNode.Value;\n            }\n\n            //update cluster nodes\n            _clusterNodes = updatedClusterNodes;\n\n            //promote self node to primary immediately\n            selfNewPrimaryNode.PromoteToPrimaryNode();\n\n            //convert cluster secondary catalog zone to catalog zone along with all its member zones\n            if (clusterCatalogZoneInfo.Type == AuthZoneType.SecondaryCatalog)\n                clusterCatalogZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.ConvertZoneTypeTo(clusterCatalogZoneInfo.Name, AuthZoneType.Catalog);\n\n            //get converted primary cluster zone info\n            clusterZoneInfo = _dnsWebService.DnsServer.AuthZoneManager.GetAuthZoneInfo(_clusterDomain);\n            if (clusterZoneInfo is null)\n                throw new DnsServerException(\"Failed to promote to Primary node: the Cluster Primary zone does not exist.\");\n\n            //sign cluster zone in case when DNSSEC private keys were not available during ConvertZoneTypeTo() operation\n            if (clusterZoneInfo.ApexZone.DnssecStatus == AuthZoneDnssecStatus.Unsigned)\n            {\n                DnssecPrivateKey kskPrivateKey = DnssecPrivateKey.Create(DnssecAlgorithm.ECDSAP256SHA256, DnssecPrivateKeyType.KeySigningKey);\n                DnssecPrivateKey zskPrivateKey = DnssecPrivateKey.Create(DnssecAlgorithm.ECDSAP256SHA256, DnssecPrivateKeyType.ZoneSigningKey);\n                zskPrivateKey.RolloverDays = 90;\n\n                _dnsWebService.DnsServer.AuthZoneManager.SignPrimaryZone(clusterZoneInfo.Name, kskPrivateKey, zskPrivateKey, 3600, false);\n            }\n\n            //find existing record TTL values\n            FindExistingRecordTtlValues(out uint nsTtl, out uint aTtl);\n\n            //remove old primary node records from cluster primary zone and save zone file\n            if (existingPrimaryNode is not null)\n                RemoveClusterPrimaryZoneRecordsFor(existingPrimaryNode);\n","sourceCodeStart":1983,"sourceCodeEnd":2019,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Cluster/ClusterManager.cs#L1983-L2019","documentation":"Thrown by PromoteToPrimaryNodeAsync after it has already converted the secondary catalog zone to a catalog zone and promoted the self node: GetAuthZoneInfo(_clusterDomain) returns null where the now-primary cluster zone is expected. Because this fires deep in the promote flow (after irreversible promotion steps), it signals that the zone-type conversion or the secondary-to-primary zone conversion did not produce the expected primary zone — a corrupt or partially-applied state.","triggerScenarios":"Promotion reached the post-conversion re-read of the cluster zone, but GetAuthZoneInfo(_clusterDomain) is null — e.g. ConvertZoneTypeTo/cleanup removed the zone, the zone file failed to persist, or the cluster domain zone was already gone and the earlier check (198) was bypassed by a code change.","commonSituations":"Disk/permission error writing the converted zone file; antivirus or another process removed the zone file mid-promotion; a bug in ConvertZoneTypeTo that leaves no primary zone; concurrent zone deletion racing with promotion. This is an internal-consistency failure more than a user-config error.","solutions":["Treat as a serious consistency failure: capture logs, then rebuild the cluster (leave+rejoin) to recreate a valid primary zone.","Check filesystem permissions and free space for the zones directory and ensure no external process (AV, sync agent) is deleting zone files.","Upgrade/review the DNS server build — this path indicates the zone-conversion did not yield the expected zone, which may be a defect.","Restore the cluster zone from backup if a known-good copy exists."],"exampleFix":"// before: bare promote that surfaces this mid-flow error\nawait clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);\n\n// after: detect the broken state and rebuild the cluster\ntry\n{\n    await clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);\n}\ncatch (DnsServerException ex) when (ex.Message.Contains(\"Cluster Primary zone does not exist\"))\n{\n    log.Error(\"Promote left cluster zone missing; rebuilding cluster.\", ex);\n    await clusterManager.LeaveClusterAsync(force: true);\n    await clusterManager.JoinClusterAsync(primaryUrl, creds, ct);\n    throw; // surface to operator for manual verify\n}","handlingStrategy":"fallback","validationCode":"// Pre-check before promoting: both cluster zones must exist and be writable\nstring catalog = \"cluster-catalog.\" + clusterManager.ClusterDomain;\nif (dnsServer.AuthZoneManager.GetAuthZoneInfo(catalog) is null\n    || dnsServer.AuthZoneManager.GetAuthZoneInfo(clusterManager.ClusterDomain) is null)\n    throw new InvalidOperationException(\"Cluster zones missing; rebuild before promoting.\");\nawait clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);","typeGuard":"static bool ClusterZonesConsistent(DnsWebService svc, string clusterDomain)\n    => svc.DnsServer.AuthZoneManager.GetAuthZoneInfo(clusterDomain) is not null\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 Primary zone does not exist\"))\n{\n    // mid-flow consistency failure: rebuild cluster from scratch\n    log.Error(\"Promote produced inconsistent zone state; rebuilding cluster.\", ex);\n    await clusterManager.LeaveClusterAsync(force: true);\n    await clusterManager.JoinClusterAsync(primaryUrl, creds, ct);\n    throw;\n}","preventionTips":["Verify zone directory permissions and free space before promoting.","Ensure no AV/sync agent deletes zone files during promotion.","Keep the DNS server patched; this path indicates a conversion defect worth reporting upstream.","Back up cluster zones before promotion so a failed convert can be restored."],"tags":["cluster","dns-zone","promote","inconsistent-state","conversion","technitium"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}