TechnitiumSoftware/DnsServer · error · InvalidOperationException
Cannot update DNSSEC records.
Error message
Cannot update DNSSEC records.
What it means
Thrown by PrimaryZone.UpdateRecord when oldRecord.Type is a DNSSEC type (DNSKEY, RRSIG, NSEC, NSEC3PARAM, NSEC3). DNSSEC records are regenerated by the signing engine, so updating them manually is rejected as InvalidOperationException. Mirrors the protections on Add/Delete.
Source
Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:2752
}
return false;
}
}
public override void UpdateRecord(DnsResourceRecord oldRecord, DnsResourceRecord newRecord)
{
switch (oldRecord.Type)
{
case DnsResourceRecordType.SOA:
throw new InvalidOperationException("Cannot update record: use SetRecords() for " + oldRecord.Type.ToString() + " record");
case DnsResourceRecordType.DNSKEY:
case DnsResourceRecordType.RRSIG:
case DnsResourceRecordType.NSEC:
case DnsResourceRecordType.NSEC3PARAM:
case DnsResourceRecordType.NSEC3:
throw new InvalidOperationException("Cannot update DNSSEC records.");
default:
if (oldRecord.Type != newRecord.Type)
throw new InvalidOperationException("Old and new record types do not match.");
if ((_dnssecStatus != AuthZoneDnssecStatus.Unsigned) && newRecord.GetAuthGenericRecordInfo().Disabled)
throw new DnsServerException("Cannot update record: disabling records in a signed zones is not supported.");
if (newRecord.OriginalTtlValue > GetZoneSoaExpire())
throw new DnsServerException("Cannot update record: TTL cannot be greater than SOA EXPIRE.");
if (!TryDeleteRecord(oldRecord.Type, oldRecord.RDATA, out DnsResourceRecord deletedRecord))
throw new DnsServerException("Cannot update record: the record does not exists to be updated.");
AddRecord(newRecord, out IReadOnlyList<DnsResourceRecord> addedRecords, out IReadOnlyList<DnsResourceRecord> deletedRecords);
List<DnsResourceRecord> allDeletedRecords = new List<DnsResourceRecord>(deletedRecords.Count + 1);
allDeletedRecords.Add(deletedRecord);View on GitHub (pinned to d0484b6c1e)
Solutions
- Exclude DNSSEC types from UpdateRecord; trigger re-signing instead.
- Branch on type so DNSSEC records are never passed to UpdateRecord.
- For key rollover, use the zone's DNSSEC private-key management API rather than record mutation.
Example fix
// before
zone.UpdateRecord(oldRecord, newRecord);
// after
if (IsDnssecType(oldRecord.Type))
throw new InvalidOperationException("DNSSEC records are managed by signing.");
zone.UpdateRecord(oldRecord, newRecord); Defensive patterns
Strategy: type-guard
Validate before calling
if (IsDnssecType(oldRecord.Type))
throw new InvalidOperationException("DNSSEC records are managed by signing.");
zone.UpdateRecord(oldRecord, newRecord); 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
- Keep DNSSEC records out of all generic update pipelines.
- Trigger re-signing to change DNSSEC material.
When it happens
Trigger: Calling zone.UpdateRecord(oldRecord, newRecord) where oldRecord.Type is a DNSSEC record type.
Common situations: Generic record-editing pipelines that handle all types uniformly; key rollover scripts that try to swap a DNSKEY via UpdateRecord.
Related errors
- Cannot delete DNSSEC records.
- Cannot update record: use SetRecords() for {type} record
- 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/e7616cebd913c191.
Report an issue: GitHub.