TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to leave Cluster: only Secondary nodes can leave the

Error message

Failed to leave Cluster: only Secondary nodes can leave the Cluster.

What it means

Thrown by LeaveClusterAsync when GetSelfNode().Type is not ClusterNodeType.Secondary. Only Secondary nodes are permitted to leave a cluster; a Primary node must be demoted or transferred (see error 182) and Unknown-typed nodes are not valid leavers. The check runs after the primary-self check, so it typically catches a node whose type is Unknown or was already promoted.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:1498

                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)
        {
            if (!ClusterInitialized)
                throw new DnsServerException("Failed to update Primary node: the Cluster is not initialized.");

            if (primaryNodeIpAddresses is null)
            {

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Confirm this is actually a Secondary node; if it was promoted to Primary, follow the primary-removal path instead.
  2. Refresh cluster state (TriggerResyncForConfig / re-login to primary) so node type is current, then retry leave.
  3. As a last resort, force-leave (forceLeave=true) only if you understand it skips primary deregistration — but still ensure the node type is Secondary first.

Example fix

// before
await clusterManager.LeaveClusterAsync(force: false);

// after
var self = clusterManager.GetSelfNode();
if (self.Type != ClusterNodeType.Secondary)
    throw new InvalidOperationException($"Cannot leave: this node is {self.Type}.");
await clusterManager.LeaveClusterAsync(force: false);
Defensive patterns

Strategy: validation

Validate before calling

var self = clusterManager.GetSelfNode();
if (self.Type != ClusterNodeType.Secondary)
    throw new InvalidOperationException($"Node is {self.Type}; only secondaries can leave.");
await clusterManager.LeaveClusterAsync(force: false);

Type guard

static bool IsSecondary(ClusterManager cm)
    => cm.ClusterInitialized && cm.GetSelfNode().Type == ClusterNodeType.Secondary;

Try / catch

try { await clusterManager.LeaveClusterAsync(force: false); }
catch (DnsServerException ex) when (ex.Message.Contains("only Secondary nodes can leave"))
{ /* node is primary or unknown; follow demote/transfer path */ }

Prevention

When it happens

Trigger: Calling LeaveClusterAsync on a node whose self type is Primary (and not detected as Self-primary by the earlier check) or Unknown — e.g. the node was just promoted to primary in-flight, or its type metadata is corrupt/uninitialized.

Common situations: State transition race where the node was promoted to Primary after the ClusterInitialized check but before the type check; a half-applied config that left Type as Unknown; operator confusion about which node they are acting on.

Related errors


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