TechnitiumSoftware/DnsServer · error · InvalidOperationException
Cannot delete SOA record.
Error message
Cannot delete SOA record.
What it means
Thrown by PrimaryZone.DeleteRecords when the requested type is DnsResourceRecordType.SOA. The SOA record is mandatory and defines zone authority, so deleting the entire RRset is treated as a programming error and surfaced as an InvalidOperationException rather than a data validation failure.
Source
Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:2683
if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
UpdateDnssecRecordsFor(this, record.Type);
TriggerNotify();
return true;
}
return false;
}
}
public override bool DeleteRecords(DnsResourceRecordType type)
{
switch (type)
{
case DnsResourceRecordType.SOA:
throw new InvalidOperationException("Cannot delete SOA record.");
case DnsResourceRecordType.DNSKEY:
case DnsResourceRecordType.RRSIG:
case DnsResourceRecordType.NSEC:
case DnsResourceRecordType.NSEC3PARAM:
case DnsResourceRecordType.NSEC3:
throw new InvalidOperationException("Cannot delete DNSSEC records.");
default:
if (_entries.TryRemove(type, out IReadOnlyList<DnsResourceRecord> removedRecords))
{
CommitAndIncrementSerial(removedRecords);
if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
UpdateDnssecRecordsFor(this, type);
TriggerNotify();
View on GitHub (pinned to d0484b6c1e)
Solutions
- Exclude DnsResourceRecordType.SOA from the set of types passed to DeleteRecords.
- Use SetRecords(SOA, newRecords) to replace the SOA RRset instead of deleting it.
- Skip SOA in any 'clear all records' helper.
Example fix
// before
foreach (var type in allTypes)
zone.DeleteRecords(type);
// after
foreach (var type in allTypes.Where(t => t != DnsResourceRecordType.SOA))
zone.DeleteRecords(type); Defensive patterns
Strategy: type-guard
Validate before calling
var protectedTypes = new[] { DnsResourceRecordType.SOA };
foreach (var type in types.Except(protectedTypes))
zone.DeleteRecords(type); Type guard
static bool IsDeletableRrsetType(DnsResourceRecordType t) =>
t != DnsResourceRecordType.SOA; Try / catch
null
Prevention
- Maintain a single 'protected types' set covering SOA and DNSSEC used by all delete calls.
- Replace SOA via SetRecords rather than delete.
- Unit-test bulk-delete helpers against a zone that contains every record type.
When it happens
Trigger: Calling zone.DeleteRecords(DnsResourceRecordType.SOA) on any PrimaryZone instance. The switch matches the SOA case before the default branch.
Common situations: Generic cleanup loops that iterate all record types and call DeleteRecords for each; bulk-delete tooling that does not exclude SOA/NS; refactoring a record-wipe routine.
Related errors
- Cannot delete DNSSEC records.
- Cannot update record: use SetRecords() for {type} record
- Cannot add record: TTL cannot be greater than SOA EXPIRE.
- Cannot update DNSSEC records.
- Cannot update record: TTL cannot be greater than SOA EXPIRE.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/24487b2a1920f855.
Report an issue: GitHub.