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 PrimaryZone.SetRecords() in the default record-type branch when records[0].OriginalTtlValue is greater than the zone's current SOA EXPIRE (GetZoneSoaExpire()). A TTL longer than EXPIRE lets resolvers cache data beyond the window secondaries guarantee valid data, so the server caps record TTLs at the zone's SOA EXPIRE.
Source
Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:2605
}
}
TriggerNotify();
break;
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 > 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.");
CommitAndIncrementSerial(deletedRecords, records);
if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
UpdateDnssecRecordsFor(this, type);
TriggerNotify();
break;
}
}
public override bool AddRecord(DnsResourceRecord record)
{
if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
{View on GitHub (pinned to d0484b6c1e)
Solutions
- Lower the record TTL to <= the zone's SOA EXPIRE before calling SetRecords.
- If a long TTL is required, raise the zone's SOA EXPIRE (via SetRecords SOA) to at least the desired TTL first.
- Clamp TTLs against GetZoneSoaExpire() when building the record set.
Example fix
// before
zone.SetRecords(type, records); // throws if TTL > SOA EXPIRE
// after
uint cap = zone.GetZoneSoaExpire();
var clamped = records.Select(r => r.OriginalTtlValue > cap
? new DnsResourceRecord(r.Name, r.Type, r.Class, cap, r.RDATA)
: r).ToList();
zone.SetRecords(type, clamped); Defensive patterns
Strategy: validation
Validate before calling
// Clamp record TTL to the zone SOA EXPIRE before SetRecords.
uint cap = zone.GetZoneSoaExpire();
records = records.Select(r => r.OriginalTtlValue > cap
? new DnsResourceRecord(r.Name, r.Type, r.Class, cap, r.RDATA)
: r).ToList();
zone.SetRecords(type, records); Type guard
static bool TtlWithinZoneExpire(IReadOnlyList<DnsResourceRecord> rs, uint soaExpire) =>
rs.Count > 0 && rs[0].OriginalTtlValue <= soaExpire; Try / catch
try { zone.SetRecords(type, records); }
catch (DnsServerException ex) when (ex.Message == "Cannot set records: TTL cannot be greater than SOA EXPIRE.")
{ Log.Error($"Clamp TTL to <= {zone.GetZoneSoaExpire()}."); } Prevention
- Clamp all record TTLs against GetZoneSoaExpire() before writing.
- When lowering SOA EXPIRE, re-evaluate existing record TTLs.
- Centralize TTL capping in the record-building helper.
When it happens
Trigger: Calling SetRecords for a normal record type (A, AAAA, MX, etc.) where the first record's TTL exceeds the zone's SOA EXPIRE value.
Common situations: Copying records with very long TTLs (e.g. 604800) into a zone with a short EXPIRE (e.g. 3600); lowering a zone's SOA EXPIRE without re-evaluating existing record TTLs; template record sets with fixed high TTLs.
Related errors
- Cannot set record: TTL cannot be greater than SOA EXPIRE.
- Cannot set record: SOA REFRESH cannot be greater than SOA EX
- Cannot add record: TTL cannot be greater than SOA EXPIRE.
- Cannot update record: TTL cannot be greater than SOA EXPIRE.
- Invalid SOA record.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/72e5a4f99420de28.
Report an issue: GitHub.