{"record":{"id":"b34b9bbeadd239a5","repo":"TechnitiumSoftware/DnsServer","slug":"failed-to-update-cluster-options-the-config-refre","errorCode":null,"errorMessage":"Failed to update Cluster options: The config refresh interval must be greater than the heartbeat refresh interval.","messagePattern":"Failed to update Cluster options: The config refresh interval must be greater than the heartbeat refresh interval\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Cluster/ClusterManager.cs","lineNumber":920,"sourceCode":"                throw new DnsServerException(\"Failed to update Cluster options: the Cluster is not initialized.\");\n\n            if (GetSelfNode().Type != ClusterNodeType.Primary)\n                throw new DnsServerException(\"Failed to update Cluster options: only the Primary node can update the Cluster options.\");\n\n            if ((heartbeatRefreshIntervalSeconds < 10) || (heartbeatRefreshIntervalSeconds > 300))\n                throw new ArgumentOutOfRangeException(nameof(heartbeatRefreshIntervalSeconds));\n\n            if ((heartbeatRetryIntervalSeconds < 10) || (heartbeatRetryIntervalSeconds > 300))\n                throw new ArgumentOutOfRangeException(nameof(heartbeatRetryIntervalSeconds));\n\n            if ((configRefreshIntervalSeconds < 30) || (configRefreshIntervalSeconds > 3600))\n                throw new ArgumentOutOfRangeException(nameof(configRefreshIntervalSeconds));\n\n            if ((configRetryIntervalSeconds < 30) || (configRetryIntervalSeconds > 3600))\n                throw new ArgumentOutOfRangeException(nameof(configRetryIntervalSeconds));\n\n            if (configRefreshIntervalSeconds <= heartbeatRefreshIntervalSeconds)\n                throw new ArgumentException(\"Failed to update Cluster options: The config refresh interval must be greater than the heartbeat refresh interval.\");\n\n            bool changed = false;\n\n            if (_heartbeatRefreshIntervalSeconds != heartbeatRefreshIntervalSeconds)\n            {\n                _heartbeatRefreshIntervalSeconds = heartbeatRefreshIntervalSeconds;\n                changed = true;\n            }\n\n            if (_heartbeatRetryIntervalSeconds != heartbeatRetryIntervalSeconds)\n            {\n                _heartbeatRetryIntervalSeconds = heartbeatRetryIntervalSeconds;\n                changed = true;\n            }\n\n            if (_configRefreshIntervalSeconds != configRefreshIntervalSeconds)\n            {\n                _configRefreshIntervalSeconds = configRefreshIntervalSeconds;","sourceCodeStart":902,"sourceCodeEnd":938,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Cluster/ClusterManager.cs#L902-L938","documentation":"UpdateClusterOptions rejects the values because configRefreshIntervalSeconds is not greater than heartbeatRefreshIntervalSeconds (configRefreshIntervalSeconds <= heartbeatRefreshIntervalSeconds). The config refresh cadence must be slower than heartbeats so health is detected before a config pull.","triggerScenarios":"Setting config refresh equal to or faster than heartbeat; lowering heartbeat without raising config; UI defaults that violate the invariant.","commonSituations":"Misordered sliders; importing a config with swapped intervals; tightening heartbeats to catch failures faster and forgetting to relax config.","solutions":["Make configRefreshIntervalSeconds strictly greater than heartbeatRefreshIntervalSeconds","Re-balance both within their bounds (heartbeat 10-300s, config 30-3600s)","Validate the invariant in the UI before submit"],"exampleFix":"// before\nclusterManager.UpdateClusterOptions(\n    heartbeatRefreshIntervalSeconds: 60,\n    heartbeatRetryIntervalSeconds: 15,\n    configRefreshIntervalSeconds: 60, // <= heartbeat: invalid\n    configRetryIntervalSeconds: 30);\n\n// after\nclusterManager.UpdateClusterOptions(\n    heartbeatRefreshIntervalSeconds: 30,\n    heartbeatRetryIntervalSeconds: 15,\n    configRefreshIntervalSeconds: 300, // > heartbeat\n    configRetryIntervalSeconds: 60);","handlingStrategy":"validation","validationCode":"if (configRefreshIntervalSeconds <= heartbeatRefreshIntervalSeconds)\n    return BadRequest(\"config refresh must be greater than heartbeat refresh.\");\nif (heartbeatRefreshIntervalSeconds is < 10 or > 300) return BadRequest(\"heartbeat out of range.\");\nif (configRefreshIntervalSeconds is < 30 or > 3600) return BadRequest(\"config out of range.\");\nclusterManager.UpdateClusterOptions(heartbeatRefreshIntervalSeconds, heartbeatRetryIntervalSeconds, configRefreshIntervalSeconds, configRetryIntervalSeconds);","typeGuard":null,"tryCatchPattern":"catch (ArgumentException ex) when (ex.Message.Contains(\"config refresh interval must be greater\"))\n{ /* surface to UI: raise config or lower heartbeat */ }","preventionTips":["Enforce config > heartbeat in the form before submission","Keep both within 10-300s (heartbeat) and 30-3600s (config) bounds"],"tags":["cluster","configuration","validation","dns-server"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}