TechnitiumSoftware/DnsServer · error · DnsWebServiceException
Cannot update record: the old record does not exists.
Error message
Cannot update record: the old record does not exists.
What it means
AuthZone.UpdateRecord calls DeleteRecord(oldType, oldRdata) to remove the old record before adding the new one. If DeleteRecord returns false — meaning no record matching the exact type and rdata was found in _entries — it throws DnsWebServiceException. This indicates the old record was already deleted, was never present, or its rdata has drifted since the caller last read it (concurrent modification).
Source
Thrown at DnsServerCore/Dns/Zones/AuthZone.cs:861
{
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:
{
//return only exact type if exists
if (_entries.TryGetValue(type, out IReadOnlyList<DnsResourceRecord> existingRecords))
{
IReadOnlyList<DnsResourceRecord> filteredRecords = FilterDisabledRecords(type, existingRecords);
if (filteredRecords.Count > 0)View on GitHub (pinned to d0484b6c1e)
Solutions
- Re-read the current record from the zone (QueryRecords) before retrying the update to get fresh rdata.
- Implement optimistic concurrency: if the old record is gone, treat it as a conflict and surface a 'record was modified by another process' message to the user.
- Use SetRecords instead of UpdateRecord if you want to replace by type without needing the exact old rdata.
Example fix
// before
zone.UpdateRecord(staleOldRecord, newRecord);
// throws: old record does not exist (was modified concurrently)
// after
var current = zone.QueryRecords(staleOldRecord.Type, false);
var match = current.FirstOrDefault(r => r.RDATA.Equals(staleOldRecord.RDATA));
if (match != null)
zone.UpdateRecord(match, newRecord);
else
zone.AddRecord(newRecord); // or report conflict Defensive patterns
Strategy: validation
Validate before calling
// Verify old record exists before attempting update
var current = zone.QueryRecords(oldRecord.Type, false);
bool exists = current.Any(r => r.RDATA.Equals(oldRecord.RDATA));
if (!exists)
throw new InvalidOperationException("Cannot update: the old record was not found. It may have been modified concurrently.");
zone.UpdateRecord(oldRecord, newRecord); Try / catch
try { zone.UpdateRecord(oldRecord, newRecord); }
catch (DnsWebServiceException ex) when (ex.Message.Contains("does not exists"))
{ /* re-read current records, surface concurrency conflict to user, or retry */ } Prevention
- Re-read the current record state before updating to detect concurrent modifications.
- Implement optimistic concurrency control with versioning or timestamp checks.
- Handle the 'old record not found' case gracefully in UI/API code with a clear conflict message.
When it happens
Trigger: Calling UpdateRecord with an oldRecord whose rdata no longer exists in the zone (was deleted by another process, expired, or the caller is working from stale data). The TryDeleteRecord method only succeeds when the exact rdata match is found.
Common situations: Concurrent zone modifications (another admin or zone transfer changed the record between read and update); stale UI state (record list was loaded, record changed server-side, then update submitted); race conditions in automated provisioning; retrying a failed update after the record was already modified.
Related errors
- Cannot add record: use SetRecords() for {type} record.
- Cannot update record: use SetRecords() for {type} record
- Old and new record types do not match.
- 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/3a4ea335ea1f8021.
Report an issue: GitHub.