TechnitiumSoftware/DnsServer · error · DnsServerException

Failed to add Secondary node: the Cluster is not initialized

Error message

Failed to add Secondary node: the Cluster is not initialized.

What it means

Thrown by JoinCluster when ClusterInitialized is false. JoinCluster adds a Secondary node to an existing cluster, which requires the cluster to already be set up with a Primary node, a primary zone, and a catalog zone. Without an initialized cluster there is nothing to join to.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:686

        public void DeleteCluster(bool forceDelete)
        {
            if (!ClusterInitialized)
                throw new DnsServerException("Failed to delete Cluster: the Cluster is not initialized.");

            if (GetSelfNode().Type != ClusterNodeType.Primary)
                throw new DnsServerException("Failed to delete Cluster: only a Primary node can delete the Cluster.");

            if (!forceDelete && (_clusterNodes.Count > 1))
                throw new DnsServerException("Failed to delete Cluster: please remove all Secondary nodes before deleting the Cluster.");

            DeleteAllClusterConfig();
        }

        public ClusterNode JoinCluster(int secondaryNodeId, Uri secondaryNodeUrl, IReadOnlyList<IPAddress> secondaryNodeIpAddresses, X509Certificate2 secondaryNodeCertificate)
        {
            if (!ClusterInitialized)
                throw new DnsServerException("Failed to add Secondary node: the Cluster is not initialized.");

            if (GetSelfNode().Type != ClusterNodeType.Primary)
                throw new DnsServerException("Failed to add Secondary node: only a Primary node can add a Secondary node to the Cluster.");

            string secondaryNodeDomain = secondaryNodeUrl.Host.ToLowerInvariant();

            if (!secondaryNodeDomain.EndsWith("." + _clusterDomain, StringComparison.OrdinalIgnoreCase))
                throw new DnsServerException("Failed to add Secondary node: the Secondary node domain name must be a subdomain of the Cluster domain name.");

            IReadOnlyDictionary<int, ClusterNode> existingClusterNodes = _clusterNodes;

            //validate for duplicate names
            foreach (KeyValuePair<int, ClusterNode> existingClusterNode in existingClusterNodes)
            {
                if (existingClusterNode.Value.Name.Equals(secondaryNodeUrl.Host, StringComparison.OrdinalIgnoreCase))
                    throw new DnsServerException("Failed to add 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.");
            }

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Initialize the cluster on the Primary node first via InitializeCluster, then call JoinCluster on that same Primary.
  2. Check ClusterManager.ClusterInitialized before calling JoinCluster.
  3. Verify the server's cluster config file loaded correctly on startup.

Example fix

// before
_dnsWebService.ClusterManager.JoinCluster(nodeId, nodeUrl, nodeIps, cert);
// after
if (!_dnsWebService.ClusterManager.ClusterInitialized)
    throw new InvalidOperationException("Initialize the cluster on the Primary node first.");
_dnsWebService.ClusterManager.JoinCluster(nodeId, nodeUrl, nodeIps, cert);
Defensive patterns

Strategy: validation

Validate before calling

if (!_dnsWebService.ClusterManager.ClusterInitialized)
    throw new InvalidOperationException("Initialize the cluster on the Primary node before joining a Secondary.");
_dnsWebService.ClusterManager.JoinCluster(nodeId, nodeUrl, nodeIps, cert);

Type guard

static bool CanJoinCluster(ClusterManager cm) => cm.ClusterInitialized;

Try / catch

try
{
    _dnsWebService.ClusterManager.JoinCluster(nodeId, nodeUrl, nodeIps, cert);
}
catch (DnsServerException ex) when (ex.Message.Contains("add Secondary node") && ex.Message.Contains("not initialized"))
{
    throw new InvalidOperationException("The cluster is not initialized. Run InitializeCluster on the Primary first.", ex);
}

Prevention

When it happens

Trigger: JoinCluster(secondaryNodeId, secondaryNodeUrl, ...) is called on a server where _clusterNodes is null or empty. The guard at line 685 fires before any Secondary-node logic runs.

Common situations: Calling JoinCluster on the wrong server (e.g., on a Secondary or a fresh server instead of the initialized Primary); the Primary's cluster config was lost or not loaded; calling join before initialize completed.

Related errors


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