TechnitiumSoftware/DnsServer · error · DnsServerException
Cannot set records: TTL cannot be greater than SOA EXPIRE.
Error message
Cannot set records: TTL cannot be greater than SOA EXPIRE.
What it means
Thrown by PrimarySubDomainZone.SetRecords() in the default case when records[0].OriginalTtlValue exceeds _primaryZone.GetZoneSoaExpire(). Enforces RFC 1035: a record TTL must not exceed the SOA EXPIRE so that secondary servers do not serve data beyond the zone's authoritative lifetime. The check uses the parent primary zone's SOA EXPIRE (the sub-domain shares the parent SOA). DnsServerException, catchable; same rule appears in ForwarderZone and PrimaryZone.
Source
Thrown at DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs:94
switch (type)
{
case DnsResourceRecordType.SOA:
throw new InvalidOperationException("Cannot set SOA record on sub domain.");
case DnsResourceRecordType.DNSKEY:
case DnsResourceRecordType.RRSIG:
case DnsResourceRecordType.NSEC:
case DnsResourceRecordType.NSEC3PARAM:
case DnsResourceRecordType.NSEC3:
throw new InvalidOperationException("Cannot set DNSSEC records.");
case DnsResourceRecordType.FWD:
throw new DnsServerException("The record type is not supported by primary zones.");
default:
if (records[0].OriginalTtlValue > _primaryZone.GetZoneSoaExpire())
throw new DnsServerException("Cannot set records: TTL cannot be greater than SOA EXPIRE.");
if (!TrySetRecords(type, records, out IReadOnlyList<DnsResourceRecord> deletedRecords))
throw new DnsServerException("Cannot set records. Please try again.");
_primaryZone.CommitAndIncrementSerial(deletedRecords, records);
if (_primaryZone.DnssecStatus != AuthZoneDnssecStatus.Unsigned)
_primaryZone.UpdateDnssecRecordsFor(this, type);
_primaryZone.TriggerNotify();
break;
}
}
public override bool AddRecord(DnsResourceRecord record)
{
if (_primaryZone.DnssecStatus != AuthZoneDnssecStatus.Unsigned)
{View on GitHub (pinned to d0484b6c1e)
Solutions
- Cap the record TTL to <= _primaryZone.GetZoneSoaExpire() before calling SetRecords.
- Raise the parent primary zone's SOA EXPIRE first if a longer TTL is required (via primaryZone.SetRecords(SOA,...)).
- Clamp TTLs at the import boundary using the parent zone's current SOA EXPIRE.
Example fix
// before
subZone.SetRecords(type, records);
// after
uint maxTtl = _primaryZone.GetZoneSoaExpire();
var clamped = records.Select(r => r.OriginalTtlValue > maxTtl
? new DnsResourceRecord(r.Name, r.Type, r.Class, maxTtl, r.RDATA) : r).ToList();
subZone.SetRecords(type, clamped); Defensive patterns
Strategy: validation
Validate before calling
uint maxTtl = _primaryZone.GetZoneSoaExpire();
if (records[0].OriginalTtlValue > maxTtl)
records = records.Select(r => new DnsResourceRecord(r.Name, r.Type, r.Class, maxTtl, r.RDATA)).ToList();
zone.SetRecords(type, records); Type guard
static bool IsTtlWithinSoaExpire(IReadOnlyList<DnsResourceRecord> records, uint soaExpire) => records.Count > 0 && records[0].OriginalTtlValue <= soaExpire;
Try / catch
try { zone.SetRecords(type, records); }
catch (DnsServerException ex) when (ex.Message.Contains("SOA EXPIRE")) { /* clamp TTL to parent SOA EXPIRE and retry */ } Prevention
- Clamp record TTLs to the parent primary zone's SOA EXPIRE before SetRecords.
- If you raise a record TTL, raise the parent SOA EXPIRE first.
- Note the sub-domain uses the PARENT zone's SOA EXPIRE, not its own.
When it happens
Trigger: subZone.SetRecords(type, records) where the first record's OriginalTtlValue > the parent primary zone's SOA EXPIRE. Triggered by importing high-TTL records or by lowering the parent SOA EXPIRE below existing record TTLs.
Common situations: Importing records with TTL 1209600+ into a zone whose SOA EXPIRE is the default; tightening SOA EXPIRE after the fact; copying records from a zone with a larger EXPIRE.
Related errors
- Cannot update record: TTL cannot be greater than SOA EXPIRE.
- The record type is not supported by DNSSEC signed primary zo
- Cannot set records: disabling records in a signed zones is n
- The record type is not supported by primary zones.
- Cannot set records. Please try again.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/fb7c6465140f38c0.
Report an issue: GitHub.