TechnitiumSoftware/DnsServer · error · DnsServerException

Cannot set record: SOA REFRESH cannot be greater than SOA EX

Error message

Cannot set record: SOA REFRESH cannot be greater than SOA EXPIRE.

What it means

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.

Source

Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:2549

                case DnsResourceRecordType.CNAME:
                case DnsResourceRecordType.DS:
                    throw new InvalidOperationException("Cannot set " + type.ToString() + " record at zone apex.");

                case DnsResourceRecordType.SOA:
                    if ((records.Count != 1) || !records[0].Name.Equals(_name, StringComparison.OrdinalIgnoreCase))
                        throw new InvalidOperationException("Invalid SOA record.");

                    DnsResourceRecord newSoaRecord = records[0];
                    DnsSOARecordData newSoa = newSoaRecord.RDATA as DnsSOARecordData;

                    if (newSoaRecord.OriginalTtlValue > newSoa.Expire)
                        throw new DnsServerException("Cannot set record: TTL cannot be greater than SOA EXPIRE.");

                    if (newSoa.Retry > newSoa.Refresh)
                        throw new DnsServerException("Cannot set record: SOA RETRY cannot be greater than SOA REFRESH.");

                    if (newSoa.Refresh > newSoa.Expire)
                        throw new DnsServerException("Cannot set record: SOA REFRESH cannot be greater than SOA EXPIRE.");

                    //remove any record info except serial date scheme and comments
                    bool useSoaSerialDateScheme;
                    string comments;
                    {
                        SOARecordInfo recordInfo = newSoaRecord.GetAuthSOARecordInfo();

                        useSoaSerialDateScheme = recordInfo.UseSoaSerialDateScheme;
                        comments = recordInfo.Comments;
                    }

                    newSoaRecord.Tag = null; //remove old record info

                    {
                        SOARecordInfo recordInfo = newSoaRecord.GetAuthSOARecordInfo();

                        recordInfo.UseSoaSerialDateScheme = useSoaSerialDateScheme;
                        recordInfo.Comments = comments;

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Set REFRESH <= EXPIRE on the SOA before calling SetRecords.
  2. If you need a longer REFRESH, raise EXPIRE to at least that value first.
  3. Validate Refresh <= Expire when constructing the SOA.

Example fix

// before
var soa = new DnsSOARecordData { Refresh = 86400, Expire = 3600 };
zone.SetRecords(DnsResourceRecordType.SOA, new[] { BuildSoaRecord(ttl, soa) }); // throws

// after
var soa = new DnsSOARecordData { Refresh = 3600, Expire = 86400 };
zone.SetRecords(DnsResourceRecordType.SOA, new[] { BuildSoaRecord(ttl, soa) });
Defensive patterns

Strategy: validation

Validate before calling

if (type == DnsResourceRecordType.SOA)
{
    var soa = (DnsSOARecordData)records[0].RDATA;
    if (soa.Refresh > soa.Expire)
        throw new ArgumentException("SOA REFRESH must be <= SOA EXPIRE.");
}

zone.SetRecords(type, records);

Type guard

static bool SoaRefreshWithinExpire(DnsResourceRecord soaRecord)
{
    var soa = (DnsSOARecordData)soaRecord.RDATA;
    return soa.Refresh <= soa.Expire;
}

Try / catch

try { zone.SetRecords(type, records); }
catch (DnsServerException ex) when (ex.Message.Contains("SOA REFRESH cannot be greater than SOA EXPIRE"))
{ Log.Error("Set SOA REFRESH <= SOA EXPIRE."); }

Prevention

When it happens

Trigger: Calling SetRecords with an SOA whose Refresh is greater than its Expire (e.g. Refresh 86400, Expire 3600).

Common situations: Aggressively lowering EXPIRE for fast staleness without lowering REFRESH; template SOA timers tuned independently and inconsistently; importing a zone whose EXPIRE was edited down.

Related errors


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