TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to update Primary node: the specified Primary node ID

Error message

Failed to update Primary node: the specified Primary node ID does not exists in the Cluster.

What it means

Thrown by UpdatePrimaryNodeAsync when a non-negative primaryNodeId was supplied but no entry with that key exists in _clusterNodes (TryGetValue returned false). The method uses primaryNodeId < 0 as 'use the current primary', so any explicit ID must match an existing cluster node's Id.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:1536

                {
                    IReadOnlyList<IPAddress> ipAddresses = await DnsClient.ResolveIPAsync(_dnsWebService.DnsServer, primaryNodeUrl.Host, _dnsWebService.DnsServer.IPv6Mode, cancellationToken);
                    if (ipAddresses.Count < 1)
                        throw new DnsServerException($"The domain name '{primaryNodeUrl.Host}' does not have an A/AAAA record configured.");

                    primaryNodeIpAddresses = ipAddresses;
                }
                catch (Exception ex)
                {
                    throw new DnsServerException($"Failed to update Primary node: the Primary node domain name '{primaryNodeUrl.Host}' could not be resolved to an IP address.", ex);
                }
            }

            ClusterNode primaryNode;

            if (primaryNodeId < 0)
                primaryNode = GetPrimaryNode();
            else if (!_clusterNodes.TryGetValue(primaryNodeId, out primaryNode))
                throw new DnsServerException("Failed to update Primary node: the specified Primary node ID does not exists in the Cluster.");

            if (primaryNode.State == ClusterNodeState.Self)
                throw new DnsServerException("Failed to update Primary node: the specified node is the self node and cannot be updated this way.");

            if (primaryNode.Type == ClusterNodeType.Secondary)
            {
                //secondary node was promoted to primary node
                ClusterNode formerPrimaryNode = GetPrimaryNode();

                //dispose former primary node immediately to stop heartbeat
                formerPrimaryNode.Dispose();

                //remove former primary node from cluster nodes
                IReadOnlyDictionary<int, ClusterNode> existingClusterNodes = _clusterNodes;
                Dictionary<int, ClusterNode> updatedClusterNodes = new Dictionary<int, ClusterNode>(existingClusterNodes.Count - 1);

                foreach (KeyValuePair<int, ClusterNode> existingClusterNode in existingClusterNodes)
                {

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Omit primaryNodeId (or pass -1) to target the current primary automatically.
  2. Refresh the cluster node list and pass a currently-valid Id from clusterManager.ClusterNodes.
  3. Validate the ID against ClusterNodes.Keys before calling the API.

Example fix

// before
await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, primaryNodeId: requestedId);

// after
if (requestedId >= 0 && !clusterManager.ClusterNodes.ContainsKey(requestedId))
    return NotFound($"Node {requestedId} not in cluster.");
await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, primaryNodeId: requestedId);
Defensive patterns

Strategy: validation

Validate before calling

if (primaryNodeId >= 0 && !clusterManager.ClusterNodes.ContainsKey(primaryNodeId))
    return NotFound($"Node {primaryNodeId} is not in the cluster.");
await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, primaryNodeId: primaryNodeId);

Type guard

static bool IsValidNodeId(ClusterManager cm, int id) => id < 0 || cm.ClusterNodes.ContainsKey(id);

Try / catch

try { await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, primaryNodeId: id); }
catch (DnsServerException ex) when (ex.Message.Contains("ID does not exists"))
{ /* refresh node list and retry with a current id, or pass -1 */ }

Prevention

When it happens

Trigger: Calling UpdatePrimaryNodeAsync with a stale, wrong, or deleted primaryNodeId — e.g. an ID from a node that has since been removed, an ID copied from a different cluster, or a default/placeholder value that happened to be non-negative.

Common situations: UI passed a cached node ID after the cluster topology changed; client serialized the wrong numeric ID; a node was deleted between the UI list load and the update submit; off-by-one or type confusion passing a port/counter as the ID.

Related errors


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