{"record":{"id":"067d8e972efc45df","repo":"TechnitiumSoftware/DnsServer","slug":"failed-to-promote-to-primary-node-only-secondary","errorCode":null,"errorMessage":"Failed to promote to Primary node: only Secondary nodes can be promoted to Primary nodes.","messagePattern":"Failed to promote to Primary node: only Secondary nodes can be promoted to Primary nodes\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Cluster/ClusterManager.cs","lineNumber":1945,"sourceCode":"            {\n                _configRetryIntervalSeconds = primaryNodeClusterInfo.ConfigRetryIntervalSeconds;\n                saveConfig = true;\n            }\n\n            //save changes\n            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)","sourceCodeStart":1927,"sourceCodeEnd":1963,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Cluster/ClusterManager.cs#L1927-L1963","documentation":"Thrown by PromoteToPrimaryNodeAsync when GetSelfNode().Type != ClusterNodeType.Secondary. Promotion is only defined for Secondary nodes becoming Primary; a node that is already Primary (or Unknown) cannot be 'promoted to primary' again. The check runs after the ClusterInitialized check.","triggerScenarios":"Calling PromoteToPrimaryNodeAsync from a node that is already the Primary, or whose type metadata is Unknown/corrupt.","commonSituations":"Operator double-clicked promote or re-ran it after success; failover already promoted this node but the runbook re-ran; node type set to Unknown by a partial config restore.","solutions":["Confirm via GetSelfNode().Type that this node is actually a Secondary before promoting.","If already Primary, no action is needed; treat as success/idempotent.","Resync config (TriggerResyncForConfig) to correct Unknown type, then retry if appropriate."],"exampleFix":"// before\nawait clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);\n\n// after\nvar self = clusterManager.GetSelfNode();\nif (self.Type == ClusterNodeType.Primary)\n    return Ok(\"Already primary.\"); // idempotent no-op\nif (self.Type != ClusterNodeType.Secondary)\n    return BadRequest($\"Cannot promote: node type is {self.Type}.\");\nawait clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);","handlingStrategy":"validation","validationCode":"var self = clusterManager.GetSelfNode();\nif (self.Type == ClusterNodeType.Primary)\n    return Ok(\"Already primary.\");\nif (self.Type != ClusterNodeType.Secondary)\n    return BadRequest($\"Cannot promote: node type is {self.Type}.\");\nawait clusterManager.PromoteToPrimaryNodeAsync(forceDeletePrimary: false);","typeGuard":"static bool IsPromotableSecondary(ClusterManager cm)\n    => cm.ClusterInitialized && cm.GetSelfNode().Type == ClusterNodeType.Secondary;","tryCatchPattern":"try { await clusterManager.PromoteToPrimaryNodeAsync(false); }\ncatch (DnsServerException ex) when (ex.Message.Contains(\"only Secondary nodes can be promoted\"))\n{ /* already primary or unknown; refresh state */ }","preventionTips":["Make promote idempotent: treat already-primary as success.","Refresh node type via resync if it shows Unknown before promoting.","Disable the promote action on non-secondary nodes."],"tags":["cluster","role-guard","promote","secondary-node","technitium"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}