{"record":{"id":"908b07908b643b2e","repo":"TechnitiumSoftware/DnsServer","slug":"failed-to-leave-cluster-the-cluster-is-not-initia","errorCode":null,"errorMessage":"Failed to leave Cluster: the Cluster is not initialized.","messagePattern":"Failed to leave Cluster: the Cluster is not initialized\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Cluster/ClusterManager.cs","lineNumber":1488,"sourceCode":"                _dnsWebService.AuthManager.SaveConfigFile();\n                SaveConfigFile();\n            }\n            finally\n            {\n                try\n                {\n                    //logout from primary node\n                    await primaryNodeApiClient.LogoutAsync(cancellationToken);\n                }\n                catch\n                { }\n            }\n        }\n\n        public async Task LeaveClusterAsync(bool forceLeave)\n        {\n            if (!ClusterInitialized)\n                throw new DnsServerException(\"Failed to leave Cluster: the Cluster is not initialized.\");\n\n            ClusterNode primaryNode = GetPrimaryNode();\n\n            if (primaryNode.State == ClusterNodeState.Self)\n                throw new DnsServerException(\"Failed to leave Cluster: a Primary self node cannot leave the Cluster.\");\n\n            ClusterNode secondaryNode = GetSelfNode();\n\n            if (secondaryNode.Type != ClusterNodeType.Secondary)\n                throw new DnsServerException(\"Failed to leave Cluster: only Secondary nodes can leave the Cluster.\");\n\n            if (!forceLeave)\n            {\n                //delete self node from cluster on primary node\n                await primaryNode.DeleteSecondaryNodeAsync(secondaryNode);\n            }\n\n            //delete all cluster config","sourceCodeStart":1470,"sourceCodeEnd":1506,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Cluster/ClusterManager.cs#L1470-L1506","documentation":"Thrown by LeaveClusterAsync at the top of the method when ClusterInitialized is false. ClusterInitialized is true only when _clusterNodes is non-null and contains at least one node, so this fires on a standalone server that has never joined (or has already fully left) a cluster. LeaveClusterAsync is meaningless without cluster state, so it aborts immediately.","triggerScenarios":"Invoking LeaveClusterAsync on a server where _clusterNodes is null or empty: a node that never joined, a node that already called LeaveClusterAsync/LeaveClusterAsync(true), or a node whose cluster config was deleted out-of-band.","commonSituations":"UI/API call to 'leave cluster' on a primary-only standalone server; re-running a leave after it already succeeded; a race where DeleteAllClusterConfig ran (e.g. on error cleanup) before the user clicked leave.","solutions":["Check ClusterManager.ClusterInitialized before calling LeaveClusterAsync and treat false as already-left.","If you expected to be clustered, inspect the cluster config file / _clusterNodes to see why state was cleared and rejoin if needed.","Make leave idempotent in the caller: guard with a pre-check so repeated clicks do not throw."],"exampleFix":"// before\nawait clusterManager.LeaveClusterAsync(force: false);\n\n// after\nif (clusterManager.ClusterInitialized)\n    await clusterManager.LeaveClusterAsync(force: false);","handlingStrategy":"validation","validationCode":"if (!clusterManager.ClusterInitialized)\n    return; // already standalone; nothing to leave\nawait clusterManager.LeaveClusterAsync(force: false);","typeGuard":"static bool IsClustered(ClusterManager cm) => cm.ClusterInitialized;","tryCatchPattern":"try { await clusterManager.LeaveClusterAsync(force: false); }\ncatch (DnsServerException ex) when (ex.Message.Contains(\"not initialized\"))\n{ /* already not clustered; treat as success */ }","preventionTips":["Make leave idempotent in your caller with a ClusterInitialized pre-check.","Disable the 'leave cluster' UI action when not clustered.","After a successful leave, refresh the displayed cluster state so a second click cannot fire."],"tags":["cluster","precondition","leave","technitium","state-guard"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}