TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to leave Cluster: a Primary self node cannot leave th

Error message

Failed to leave Cluster: a Primary self node cannot leave the Cluster.

What it means

Thrown by LeaveClusterAsync when the primary node resolved by GetPrimaryNode() has State == ClusterNodeState.Self, i.e. this server is itself the cluster primary. A primary node cannot 'leave' its own cluster because leaving implies deregistering from a remote primary; the primary must instead transfer/demote. The guard stops an operator from orphaning the cluster.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:1493

                try
                {
                    //logout from primary node
                    await primaryNodeApiClient.LogoutAsync(cancellationToken);
                }
                catch
                { }
            }
        }

        public async Task LeaveClusterAsync(bool forceLeave)
        {
            if (!ClusterInitialized)
                throw new DnsServerException("Failed to leave Cluster: the Cluster is not initialized.");

            ClusterNode primaryNode = GetPrimaryNode();

            if (primaryNode.State == ClusterNodeState.Self)
                throw new DnsServerException("Failed to leave Cluster: a Primary self node cannot leave the Cluster.");

            ClusterNode secondaryNode = GetSelfNode();

            if (secondaryNode.Type != ClusterNodeType.Secondary)
                throw new DnsServerException("Failed to leave Cluster: only Secondary nodes can leave the Cluster.");

            if (!forceLeave)
            {
                //delete self node from cluster on primary node
                await primaryNode.DeleteSecondaryNodeAsync(secondaryNode);
            }

            //delete all cluster config
            DeleteAllClusterConfig();
        }

        public async Task<ClusterNode> UpdatePrimaryNodeAsync(Uri primaryNodeUrl, IReadOnlyList<IPAddress> primaryNodeIpAddresses = null, int primaryNodeId = -1, CancellationToken cancellationToken = default)
        {

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Promote a secondary to primary first (PromoteToPrimaryNodeAsync on a secondary, or transfer primary), then leave from the now-secondary node.
  2. If you intend to dissolve the cluster entirely, delete all cluster config / disband from the primary instead of calling leave.
  3. In shared automation, branch on node type: only secondaries call LeaveClusterAsync.

Example fix

// before: same leave path for every node
await clusterManager.LeaveClusterAsync(force: false);

// after: only secondaries leave; primary must be demoted/transferred first
if (clusterManager.GetPrimaryNode().State == ClusterNodeState.Self)
    throw new InvalidOperationException("Demote/transfer primary before leaving.");
await clusterManager.LeaveClusterAsync(force: false);
Defensive patterns

Strategy: validation

Validate before calling

if (clusterManager.GetPrimaryNode().State == ClusterNodeState.Self)
    throw new InvalidOperationException("Demote or transfer primary before leaving.");
await clusterManager.LeaveClusterAsync(force: false);

Type guard

static bool IsSelfPrimary(ClusterManager cm)
    => cm.ClusterInitialized && cm.GetPrimaryNode().State == ClusterNodeState.Self;

Try / catch

try { await clusterManager.LeaveClusterAsync(force: false); }
catch (DnsServerException ex) when (ex.Message.Contains("Primary self node cannot leave"))
{ /* instruct operator to promote a secondary first */ }

Prevention

When it happens

Trigger: Calling LeaveClusterAsync from the server that currently holds the Primary role (GetPrimaryNode().State == Self).

Common situations: Operator on the primary node clicks 'Leave Cluster'; automation script runs the same leave routine on every cluster member including the primary; failover left this node as primary but the runbook still calls leave.

Related errors


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