TechnitiumSoftware/DnsServer · warning · DnsServerException

Failed to refresh configuration: only Secondary nodes can sy

Error message

Failed to refresh configuration: only Secondary nodes can sync configuration from Primary nodes.

What it means

Thrown by the public TriggerRefreshForConfig when GetPrimaryNode().State == ClusterNodeState.Self — i.e. this server is itself the primary. Secondary-to-primary config sync is the whole point of refresh, so a primary node has no upstream to pull from. The guard prevents a primary from trying to sync config from itself.

Source

Thrown at DnsServerCore/Cluster/ClusterManager.cs:1613

            _dnsWebService.DnsServer.AuthZoneManager.SaveZoneFile(clusterSecondaryCatalogZoneInfo.Name);
            SaveConfigFile();

            //trigger config and zone refresh
            TriggerRefreshForConfig(CONFIG_REFRESH_TIMER_INTERVAL);

            return primaryNode;
        }

        public void TriggerRefreshForConfig(IReadOnlyCollection<string> configRefreshIncludeZones = null)
        {
            //do validation
            if (!ClusterInitialized)
                throw new DnsServerException("Failed to refresh configuration: the Cluster is not initialized.");

            ClusterNode primaryNode = GetPrimaryNode();

            if (primaryNode.State == ClusterNodeState.Self)
                throw new DnsServerException("Failed to refresh configuration: only Secondary nodes can sync configuration from Primary nodes.");

            TriggerRefreshForConfig(CONFIG_REFRESH_TIMER_INTERVAL, configRefreshIncludeZones);
        }

        public void TriggerResyncForConfig()
        {
            //do validation
            if (!ClusterInitialized)
                throw new DnsServerException("Failed to resync configuration: the Cluster is not initialized.");

            ClusterNode primaryNode = GetPrimaryNode();

            if (primaryNode.State == ClusterNodeState.Self)
                throw new DnsServerException("Failed to resync configuration: only Secondary nodes can sync configuration from Primary nodes.");

            _configLastSynced = DateTime.UnixEpoch; //to ensure complete config resync

            //trigger immediate config refresh

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Only call TriggerRefreshForConfig from Secondary nodes; on the primary it is a no-op by definition.
  2. In shared jobs, branch on whether GetPrimaryNode().State == Self and skip refresh there.
  3. Hide/disable the refresh action when the current node is the primary.

Example fix

// before
clusterManager.TriggerRefreshForConfig(includeZones);

// after
if (clusterManager.GetPrimaryNode().State == ClusterNodeState.Self)
    return Ok("Primary node; nothing to refresh."); // no-op
clusterManager.TriggerRefreshForConfig(includeZones);
Defensive patterns

Strategy: validation

Validate before calling

if (clusterManager.GetPrimaryNode().State == ClusterNodeState.Self)
    return Ok("Primary node; nothing to refresh.");
clusterManager.TriggerRefreshForConfig(includeZones);

Type guard

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

Try / catch

try { clusterManager.TriggerRefreshForConfig(includeZones); }
catch (DnsServerException ex) when (ex.Message.Contains("only Secondary nodes can sync"))
{ /* running on primary; refresh is a no-op */ }

Prevention

When it happens

Trigger: Calling TriggerRefreshForConfig on the primary node of the cluster (GetPrimaryNode() is Self).

Common situations: The same admin console is used for primary and secondary nodes and the refresh button was clicked while logged into the primary; automation runs a periodic 'refresh config' job on every cluster member without checking role.

Related errors


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