TechnitiumSoftware/DnsServer · error · InvalidOperationException
Cannot delete DNSSEC records.
Error message
Cannot delete DNSSEC records.
What it means
Thrown by PrimaryZone.DeleteRecords when the requested type is one of the DNSSEC record types (DNSKEY, RRSIG, NSEC, NSEC3PARAM, NSEC). DNSSEC records are managed internally by the signing engine (UpdateDnssecRecordsFor), so manual deletion is rejected as a programming error.
Source
Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:2690
}
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();
return true;
}
return false;
}
}
View on GitHub (pinned to d0484b6c1e)
Solutions
- Filter DNSSEC types (DNSKEY, RRSIG, NSEC, NSEC3PARAM, NSEC3) out before calling DeleteRecords.
- To remove DNSSEC data, change the zone's DNSSEC status / re-sign rather than deleting individual RRs.
- Maintain an IsDnssecType(type) helper and guard all bulk operations with it.
Example fix
// before
foreach (var type in allTypes)
zone.DeleteRecords(type);
// after
var dnssec = new[]{ DnsResourceRecordType.DNSKEY, DnsResourceRecordType.RRSIG,
DnsResourceRecordType.NSEC, DnsResourceRecordType.NSEC3PARAM, DnsResourceRecordType.NSEC3 };
foreach (var type in allTypes.Except(dnssec).Append(SOA-blacklist))
zone.DeleteRecords(type); Defensive patterns
Strategy: type-guard
Validate before calling
static readonly HashSet<DnsResourceRecordType> DnssecTypes = new()
{
DnsResourceRecordType.DNSKEY, DnsResourceRecordType.RRSIG,
DnsResourceRecordType.NSEC, DnsResourceRecordType.NSEC3PARAM,
DnsResourceRecordType.NSEC3
};
foreach (var type in types.Where(t => !DnssecTypes.Contains(t) && t != DnsResourceRecordType.SOA))
zone.DeleteRecords(type); Type guard
static bool IsDnssecType(DnsResourceRecordType t) =>
t == DnsResourceRecordType.DNSKEY || t == DnsResourceRecordType.RRSIG ||
t == DnsResourceRecordType.NSEC || t == DnsResourceRecordType.NSEC3PARAM ||
t == DnsResourceRecordType.NSEC3; Try / catch
null
Prevention
- Centralize IsDnssecType() and reuse it across add/delete/update guards.
- Drive DNSSEC record lifecycle only through the signing engine, never manual deletes.
- When changing zone signed status, expect the engine to rewrite DNSSEC RRs.
When it happens
Trigger: Calling zone.DeleteRecords(type) where type is DNSKEY, RRSIG, NSEC, NSEC3PARAM, or NSEC3 on a PrimaryZone.
Common situations: Generic delete-all loops that sweep every type; tooling that treats DNSSEC records like normal RRs; switching a zone out of signed mode and trying to strip records by hand.
Related errors
- Cannot delete SOA record.
- Cannot update DNSSEC records.
- No such primary zone was found: <zoneName>
- The record type is not supported by DNSSEC signed primary zo
- Cannot set records: disabling records in a signed zones is n
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/6c98db08ef797735.
Report an issue: GitHub.