TechnitiumSoftware/DnsServer · error · InvalidOperationException
Old and new record types do not match.
Error message
Old and new record types do not match.
What it means
Thrown by PrimarySubDomainZone.UpdateRecord when oldRecord.Type != newRecord.Type. UpdateRecord is a same-type replace (delete-old/add-new at the same RRset), so a type change is undefined; the guard rejects it with InvalidOperationException before any state mutation.
Source
Thrown at DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs:233
}
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 ((_primaryZone.DnssecStatus != AuthZoneDnssecStatus.Unsigned) && newRecord.GetAuthGenericRecordInfo().Disabled)
throw new DnsServerException("Cannot update record: disabling records in a signed zones is not supported.");
if (newRecord.OriginalTtlValue > _primaryZone.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 InvalidOperationException("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);
allDeletedRecords.AddRange(deletedRecords);
_primaryZone.CommitAndIncrementSerial(allDeletedRecords, addedRecords);
View on GitHub (pinned to d0484b6c1e)
Solutions
- Ensure old and new share the same Type before calling UpdateRecord.
- For a genuine type change, delete the old record and add the new one as separate operations.
- Validate the pairing in the caller so mismatched types never reach the API.
Example fix
// before
zone.UpdateRecord(oldARecord, newAaaaRecord);
// after
if (oldRecord.Type != newRecord.Type)
{
zone.DeleteRecord(oldRecord.Type, oldRecord.RDATA);
zone.AddRecord(newRecord);
}
else
zone.UpdateRecord(oldRecord, newRecord); Defensive patterns
Strategy: validation
Validate before calling
if (oldRecord.Type != newRecord.Type)
throw new InvalidOperationException("Record types differ; delete + add instead.");
zone.UpdateRecord(oldRecord, newRecord); Type guard
static bool SameRecordType(DnsResourceRecord a, DnsResourceRecord b) => a.Type == b.Type;
Prevention
- Assert oldRecord.Type == newRecord.Type before UpdateRecord.
- For type migrations, delete then add rather than update.
- Pair records by (name, type) in import pipelines.
When it happens
Trigger: zone.UpdateRecord(oldRecord, newRecord) where the two records differ in Type (e.g., old is A, new is AAAA).
Common situations: Mis-ordered arguments; 'migrating' a name from one record type to another via Update instead of delete+add; record-import pipelines that recompute type per row.
Related errors
- Cannot delete DNSSEC records.
- Cannot update record: use SetRecords() for {oldRecord.Type}
- Cannot update DNSSEC records.
- Cannot update record: disabling records in a signed zones is
- Cannot update record: the record does not exists to be updat
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/49172a3fb54134c6.
Report an issue: GitHub.