TechnitiumSoftware/DnsServer · error · InvalidOperationException
Cannot update record: use SetRecords() for {type} record
Error message
Cannot update record: use SetRecords() for {type} record What it means
AuthZone.UpdateRecord rejects SOA record updates with InvalidOperationException. The SOA (Start of Authority) record is a singleton that defines zone-wide parameters (serial, refresh, retry, expire, minimum) and has special semantics for zone transfers and DNSSEC. UpdateRecord performs a delete-then-add sequence that is unsafe for SOA; the library requires SetRecords() which atomically replaces the single SOA record.
Source
Thrown at DnsServerCore/Dns/Zones/AuthZone.cs:855
AddRecord(record, out IReadOnlyList<DnsResourceRecord> addedRecords, out _);
return addedRecords.Count > 0;
}
public virtual bool DeleteRecords(DnsResourceRecordType type)
{
return _entries.TryRemove(type, out _);
}
public virtual bool DeleteRecord(DnsResourceRecordType type, DnsResourceRecordData rdata)
{
return TryDeleteRecord(type, rdata, out _);
}
public virtual void UpdateRecord(DnsResourceRecord oldRecord, DnsResourceRecord newRecord)
{
if (oldRecord.Type == DnsResourceRecordType.SOA)
throw new InvalidOperationException("Cannot update record: use SetRecords() for " + oldRecord.Type.ToString() + " record");
if (oldRecord.Type != newRecord.Type)
throw new InvalidOperationException("Old and new record types do not match.");
if (!DeleteRecord(oldRecord.Type, oldRecord.RDATA))
throw new DnsWebServiceException("Cannot update record: the old record does not exists.");
AddRecord(newRecord);
}
public virtual IReadOnlyList<DnsResourceRecord> QueryRecords(DnsResourceRecordType type, bool dnssecOk)
{
switch (type)
{
case DnsResourceRecordType.APP:
case DnsResourceRecordType.FWD:
case DnsResourceRecordType.NSEC:
case DnsResourceRecordType.NSEC3:View on GitHub (pinned to d0484b6c1e)
Solutions
- Use SetRecords(DnsResourceRecordType.SOA, [newSoaRecord]) to replace the SOA record atomically.
- Use the zone's dedicated SOA management methods if available (e.g., serial increment, timer adjustment APIs).
- Add a type guard before calling UpdateRecord to route SOA records to SetRecords.
Example fix
// before
zone.UpdateRecord(oldSoaRecord, newSoaRecord);
// throws: use SetRecords() for SOA record
// after
zone.SetRecords(DnsResourceRecordType.SOA, new[] { newSoaRecord }); Defensive patterns
Strategy: type-guard
Validate before calling
if (oldRecord.Type == DnsResourceRecordType.SOA)
zone.SetRecords(DnsResourceRecordType.SOA, new[] { newRecord });
else
zone.UpdateRecord(oldRecord, newRecord); Type guard
static bool CanUpdateRecord(DnsResourceRecordType type)
=> type != DnsResourceRecordType.SOA; Prevention
- Route SOA modifications through SetRecords in all code paths.
- Add a type check before UpdateRecord to dispatch SOA correctly.
- Use zone-specific SOA management APIs for serial/timer changes.
When it happens
Trigger: Calling UpdateRecord with oldRecord.Type == DnsResourceRecordType.SOA. This occurs when zone-management code attempts to modify SOA parameters (e.g., changing refresh interval or serial number) through the generic UpdateRecord API.
Common situations: Zone management UI/API that routes all record edits through a single UpdateRecord handler; scripts adjusting SOA timers; DNSSEC key rollover workflows that attempt SOA updates generically.
Related errors
- Cannot add record: use SetRecords() for {type} record.
- Old and new record types do not match.
- Cannot update record: the old record does not exists.
- Zone was not found for domain: {key}
- Zone does not contain SOA record.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/63d3d8890df43732.
Report an issue: GitHub.