TechnitiumSoftware/DnsServer · error · DnsServerException
Cannot update record: the record does not exists to be updat
Error message
Cannot update record: the record does not exists to be updated.
What it means
Thrown by ForwarderZone.UpdateRecord() when TryDeleteRecord(oldRecord.Type, oldRecord.RDATA) returns false, meaning no existing record matched the old record's (type, rdata) pair. UpdateRecord is implemented as delete-old-then-add-new inside one commit; if the old record is absent there is nothing to update and the add-then-commit would silently create a record without removing one, so the operation is rejected. The message notes the record 'does not exists' (sic) to be updated. DnsServerException, so catchable by API clients.
Source
Thrown at DnsServerCore/Dns/Zones/ForwarderZone.cs:253
}
}
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");
default:
if (oldRecord.Type != newRecord.Type)
throw new InvalidOperationException("Old and new record types do not match.");
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);
allDeletedRecords.AddRange(deletedRecords);
CommitAndIncrementSerial(allDeletedRecords, addedRecords);
TriggerNotify();
break;
}
}
public override IReadOnlyList<DnsResourceRecord> QueryRecords(DnsResourceRecordType type, bool dnssecOk)
{
if (this is CatalogZone)
return base.QueryRecords(type, dnssecOk);View on GitHub (pinned to d0484b6c1e)
Solutions
- Re-fetch the current record set (QueryRecords) immediately before updating and rebuild oldRecord from the live entry so its RDATA matches exactly.
- If the old record is genuinely gone, switch to AddRecord(newRecord) instead of UpdateRecord.
- Handle this as a known concurrent-edit case: return a 409 Conflict to the client and let them refresh.
Example fix
// before
zone.UpdateRecord(staleOldRecord, newRecord);
// after
var live = zone.QueryRecords(type, false)
.FirstOrDefault(r => r.RDATA.Equals(staleOldRecord.RDATA));
if (live == null)
zone.AddRecord(newRecord); // old gone -> create instead
else
zone.UpdateRecord(live, newRecord); Defensive patterns
Strategy: validation
Validate before calling
var live = zone.QueryRecords(oldRecord.Type, false).FirstOrDefault(r => r.RDATA.Equals(oldRecord.RDATA));
if (live == null) { zone.AddRecord(newRecord); return; }
zone.UpdateRecord(live, newRecord); Type guard
static bool RecordStillExists(Zone zone, DnsResourceRecord oldRecord) => zone.QueryRecords(oldRecord.Type, false).Any(r => r.RDATA.Equals(oldRecord.RDATA));
Try / catch
try { zone.UpdateRecord(oldRecord, newRecord); }
catch (DnsServerException ex) when (ex.Message.Contains("does not exists")) { zone.AddRecord(newRecord); } Prevention
- Re-query the record set immediately before updating and pass the live record as oldRecord.
- Treat 'does not exist' as a concurrent-edit signal; return 409 and let the client refresh.
- Normalize RDATA (case, trailing dots) when matching to avoid false misses.
When it happens
Trigger: Calling zone.UpdateRecord(oldRecord, newRecord) where oldRecord no longer exists in the zone (already deleted, or RDATA does not byte-match an entry), or where oldRecord was constructed with RDATA that differs from the stored record (e.g. canonicalized differently). Concurrent modification between a list-query and the update also produces this.
Common situations: Stale client view: user lists records, another process deletes one, user submits an edit on the deleted record; RDATA normalization differences (case, compression, trailing dot) causing TryDeleteRecord to miss; retrying an update after a partial failure.
Related errors
- Old and new record types do not match.
- Cannot update record: TTL cannot be greater than SOA EXPIRE.
- Cannot set records. Please try again.
- Value cannot be less than 1.
- Valid range is from 1 to 4.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/d5a2b97beabf5bcd.
Report an issue: GitHub.