TechnitiumSoftware/DnsServer · error · DnsServerException

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

Error message

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

What it means

Thrown by PrimaryZone.SetRecords() in the SOA case when the new SOA record's TTL (OriginalTtlValue) is greater than the new SOA EXPIRE value. Per DNS semantics, a resolver could cache the record longer than the EXPIRE window in which secondary servers are guaranteed to have valid data, causing stale answers; the server enforces TTL <= EXPIRE.

Source

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

                        break;
                }
            }

            switch (type)
            {
                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

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Set the SOA TTL to a value <= the SOA EXPIRE before calling SetRecords.
  2. If you need a long TTL, raise EXPIRE to at least that value first (subject to the REFRESH <= EXPIRE constraint).
  3. Validate OriginalTtlValue <= Expire on the constructed SOA before submission.

Example fix

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

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

Strategy: validation

Validate before calling

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

zone.SetRecords(type, records);

Type guard

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

Try / catch

try { zone.SetRecords(type, records); }
catch (DnsServerException ex) when (ex.Message == "Cannot set record: TTL cannot be greater than SOA EXPIRE.")
{ Log.Error("Lower the SOA TTL or raise SOA EXPIRE."); }

Prevention

When it happens

Trigger: Calling SetRecords with an SOA whose OriginalTtlValue > newSoa.Expire (e.g. TTL 86400 but EXPIRE 3600).

Common situations: Copying a high-TTL SOA from another zone into one with a short EXPIRE; lowering EXPIRE for faster failover without also lowering the SOA TTL; template values where TTL and EXPIRE were set independently and inconsistently.

Related errors


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