{"record":{"id":"4cedbc3ccf99ead5","repo":"TechnitiumSoftware/DnsServer","slug":"cannot-set-record-soa-refresh-cannot-be-greater-t-4cedbc","errorCode":null,"errorMessage":"Cannot set record: SOA REFRESH cannot be greater than SOA EXPIRE.","messagePattern":"Cannot set record: SOA REFRESH cannot be greater than SOA EXPIRE\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Zones/PrimaryZone.cs","lineNumber":2549,"sourceCode":"                case DnsResourceRecordType.CNAME:\n                case DnsResourceRecordType.DS:\n                    throw new InvalidOperationException(\"Cannot set \" + type.ToString() + \" record at zone apex.\");\n\n                case DnsResourceRecordType.SOA:\n                    if ((records.Count != 1) || !records[0].Name.Equals(_name, StringComparison.OrdinalIgnoreCase))\n                        throw new InvalidOperationException(\"Invalid SOA record.\");\n\n                    DnsResourceRecord newSoaRecord = records[0];\n                    DnsSOARecordData newSoa = newSoaRecord.RDATA as DnsSOARecordData;\n\n                    if (newSoaRecord.OriginalTtlValue > newSoa.Expire)\n                        throw new DnsServerException(\"Cannot set record: TTL cannot be greater than SOA EXPIRE.\");\n\n                    if (newSoa.Retry > newSoa.Refresh)\n                        throw new DnsServerException(\"Cannot set record: SOA RETRY cannot be greater than SOA REFRESH.\");\n\n                    if (newSoa.Refresh > newSoa.Expire)\n                        throw new DnsServerException(\"Cannot set record: SOA REFRESH cannot be greater than SOA EXPIRE.\");\n\n                    //remove any record info except serial date scheme and comments\n                    bool useSoaSerialDateScheme;\n                    string comments;\n                    {\n                        SOARecordInfo recordInfo = newSoaRecord.GetAuthSOARecordInfo();\n\n                        useSoaSerialDateScheme = recordInfo.UseSoaSerialDateScheme;\n                        comments = recordInfo.Comments;\n                    }\n\n                    newSoaRecord.Tag = null; //remove old record info\n\n                    {\n                        SOARecordInfo recordInfo = newSoaRecord.GetAuthSOARecordInfo();\n\n                        recordInfo.UseSoaSerialDateScheme = useSoaSerialDateScheme;\n                        recordInfo.Comments = comments;","sourceCodeStart":2531,"sourceCodeEnd":2567,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimaryZone.cs#L2531-L2567","documentation":"Thrown by PrimaryZone.SetRecords() in the SOA case when newSoa.Refresh > newSoa.Expire. REFRESH is how often a secondary polls the primary; EXPIRE is how long secondary data remains valid without a successful refresh. If REFRESH exceeds EXPIRE, a zone could expire before the next scheduled refresh, so the server enforces REFRESH <= EXPIRE.","triggerScenarios":"Calling SetRecords with an SOA whose Refresh is greater than its Expire (e.g. Refresh 86400, Expire 3600).","commonSituations":"Aggressively lowering EXPIRE for fast staleness without lowering REFRESH; template SOA timers tuned independently and inconsistently; importing a zone whose EXPIRE was edited down.","solutions":["Set REFRESH <= EXPIRE on the SOA before calling SetRecords.","If you need a longer REFRESH, raise EXPIRE to at least that value first.","Validate Refresh <= Expire when constructing the SOA."],"exampleFix":"// before\nvar soa = new DnsSOARecordData { Refresh = 86400, Expire = 3600 };\nzone.SetRecords(DnsResourceRecordType.SOA, new[] { BuildSoaRecord(ttl, soa) }); // throws\n\n// after\nvar soa = new DnsSOARecordData { Refresh = 3600, Expire = 86400 };\nzone.SetRecords(DnsResourceRecordType.SOA, new[] { BuildSoaRecord(ttl, soa) });","handlingStrategy":"validation","validationCode":"if (type == DnsResourceRecordType.SOA)\n{\n    var soa = (DnsSOARecordData)records[0].RDATA;\n    if (soa.Refresh > soa.Expire)\n        throw new ArgumentException(\"SOA REFRESH must be <= SOA EXPIRE.\");\n}\n\nzone.SetRecords(type, records);","typeGuard":"static bool SoaRefreshWithinExpire(DnsResourceRecord soaRecord)\n{\n    var soa = (DnsSOARecordData)soaRecord.RDATA;\n    return soa.Refresh <= soa.Expire;\n}","tryCatchPattern":"try { zone.SetRecords(type, records); }\ncatch (DnsServerException ex) when (ex.Message.Contains(\"SOA REFRESH cannot be greater than SOA EXPIRE\"))\n{ Log.Error(\"Set SOA REFRESH <= SOA EXPIRE.\"); }","preventionTips":["Keep REFRESH <= EXPIRE in SOA templates.","When lowering EXPIRE, re-check REFRESH.","Validate the full REFRESH/RETRY/EXPIRE/TTL ordering before writing SOA."],"tags":["dns","record","soa","refresh","expire","validation"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}