{"record":{"id":"df1b3830f308ad3e","repo":"TechnitiumSoftware/DnsServer","slug":"failed-to-update-secondary-node-only-a-primary-no","errorCode":null,"errorMessage":"Failed to update Secondary node: only a Primary node can update a Secondary node's details in the Cluster.","messagePattern":"Failed to update Secondary node: only a Primary node can update a Secondary node's details in the Cluster\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Cluster/ClusterManager.cs","lineNumber":822,"sourceCode":"            //save all changes\n            SaveConfigFile();\n\n            //notify all secondary nodes\n            TriggerNotifyAllSecondaryNodes();\n\n            //trigger NS and SOA update for member zones\n            TriggerRecordUpdateForClusterCatalogMemberZones();\n\n            return secondaryNode;\n        }\n\n        public ClusterNode UpdateSecondaryNode(int secondaryNodeId, Uri secondaryNodeUrl, IReadOnlyList<IPAddress> secondaryNodeIpAddresses, X509Certificate2 secondaryNodeCertificate)\n        {\n            if (!ClusterInitialized)\n                throw new DnsServerException(\"Failed to update Secondary node: the Cluster is not initialized.\");\n\n            if (GetSelfNode().Type != ClusterNodeType.Primary)\n                throw new DnsServerException(\"Failed to update Secondary node: only a Primary node can update a Secondary node's details in the Cluster.\");\n\n            IReadOnlyDictionary<int, ClusterNode> clusterNodes = _clusterNodes;\n\n            if (!clusterNodes.TryGetValue(secondaryNodeId, out ClusterNode secondaryNode))\n                throw new DnsServerException(\"Failed to update Secondary node: the specified node does not exist in the Cluster.\");\n\n            if (secondaryNode.Type != ClusterNodeType.Secondary)\n                throw new DnsServerException(\"Failed to update Secondary node: the specified node to update must be a Secondary node.\");\n\n            //validate for duplicate names\n            foreach (KeyValuePair<int, ClusterNode> clusterNode in clusterNodes)\n            {\n                if (clusterNode.Key == secondaryNodeId)\n                    continue; //skip self\n\n                if (clusterNode.Value.Name.Equals(secondaryNodeUrl.Host, StringComparison.OrdinalIgnoreCase))\n                    throw new DnsServerException(\"Failed to update Secondary node: A node with the same DNS Server Domain Name already exists in the Cluster. Please try again after changing the Secondary node's DNS Server Domain Name.\");\n            }","sourceCodeStart":804,"sourceCodeEnd":840,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Cluster/ClusterManager.cs#L804-L840","documentation":"UpdateSecondaryNode is only permitted on the node acting as cluster Primary (GetSelfNode().Type == Primary). Calling it from a Secondary or standalone node is rejected because Secondary nodes cannot edit cluster topology.","triggerScenarios":"Running the update against a Secondary node's API; an L4 load balancer routing the request to the wrong cluster member; the server was demoted from Primary to Secondary after the client cached its role.","commonSituations":"Failover or demotion changing which node is Primary mid-session; client targeting a node by IP rather than by role; split-brain where the client talks to a Secondary.","solutions":["Target the current Primary node - discover it via cluster state and call its API","Refresh the client's notion of which node is Primary before issuing topology edits","Re-run the call against the correct endpoint"],"exampleFix":"// before\nclusterManager.UpdateSecondaryNode(id, url, ips, cert);\n\n// after\nif (clusterManager.GetSelfNode().Type != ClusterNodeType.Primary)\n    throw new InvalidOperationException(\"This node is not the Primary; redirect to the Primary.\");\nclusterManager.UpdateSecondaryNode(id, url, ips, cert);","handlingStrategy":"validation","validationCode":"if (clusterManager.GetSelfNode().Type != ClusterNodeType.Primary)\n    return RedirectOrReject(\"Only the Primary node can update Secondary nodes.\");\nclusterManager.UpdateSecondaryNode(id, url, ips, cert);","typeGuard":null,"tryCatchPattern":"catch (DnsServerException ex) when (ex.Message.Contains(\"only a Primary node can update\"))\n{ /* rediscover Primary and retry there */ }","preventionTips":["Have clients discover the Primary via cluster state and pin topology calls to it","Re-check role right before the call if failover is possible"],"tags":["cluster","primary-node","authorization","validation","dns-server"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}