TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to update Primary node: the specified node is the sel

Error message

Failed to update Primary node: the specified node is the self node and cannot be updated this way.

What it means

Thrown by UpdatePrimaryNodeAsync when the node selected by primaryNodeId resolves to the self node (primaryNode.State == ClusterNodeState.Self). UpdatePrimaryNodeAsync is meant to point at a *remote* primary; updating the self node's own address via this API is not permitted because it would rewrite the local node's identity from under itself.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:1539

                        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)
                {
                    if (existingClusterNode.Key == formerPrimaryNode.Id)
                        continue;

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Select a different, remote node Id (or pass -1 if you genuinely mean the current remote primary).
  2. Filter the self node out of any 'pick primary' UI list before submission.
  3. If you meant to change this server's own advertised URL, use the node's own UpdateNode path rather than UpdatePrimaryNodeAsync.

Example fix

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

// after
if (clusterManager.ClusterNodes[pickedId].State == ClusterNodeState.Self)
    return BadRequest("Cannot target the self node via update-primary.");
await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, primaryNodeId: pickedId);
Defensive patterns

Strategy: validation

Validate before calling

if (primaryNodeId >= 0 && clusterManager.ClusterNodes[primaryNodeId].State == ClusterNodeState.Self)
    return BadRequest("Cannot target the self node via update-primary.");
await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, primaryNodeId: primaryNodeId);

Type guard

static bool IsSelfNodeId(ClusterManager cm, int id)
    => id >= 0 && cm.ClusterNodes.TryGetValue(id, out var n) && n.State == ClusterNodeState.Self;

Try / catch

try { await clusterManager.UpdatePrimaryNodeAsync(primaryUrl, primaryNodeId: id); }
catch (DnsServerException ex) when (ex.Message.Contains("self node and cannot be updated"))
{ /* pick a remote node id instead */ }

Prevention

When it happens

Trigger: Passing a primaryNodeId that equals this server's own node Id, on a server that is currently the primary (so GetPrimaryNode() is Self).

Common situations: Operator selected their own node in a 'choose new primary' dropdown; automation passed the self node's Id by mistake; the cluster has only one node and the caller tried to 'update' it.

Related errors


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