{"record":{"id":"aa9dea3b8b87998f","repo":"TechnitiumSoftware/DnsServer","slug":"cannot-update-record-the-old-record-does-not-exis","errorCode":null,"errorMessage":"Cannot update record: the old record does not exists.","messagePattern":"Cannot update record: the old record does not exists\\.","errorType":"exception","errorClass":"DnsWebServiceException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs","lineNumber":2357,"sourceCode":"                        newZone.SetRecords(newRecord.Type, new DnsResourceRecord[] { newRecord });\n\n                        if (newZone is SubDomainZone subDomainZone1)\n                            subDomainZone1.AutoUpdateState();\n                    }\n                    break;\n\n                default:\n                    if (oldRecord.Name.Equals(newRecord.Name, StringComparison.OrdinalIgnoreCase))\n                    {\n                        authZone.UpdateRecord(oldRecord, newRecord);\n\n                        if (authZone is SubDomainZone subDomainZone)\n                            subDomainZone.AutoUpdateState();\n                    }\n                    else\n                    {\n                        if (!authZone.DeleteRecord(oldRecord.Type, oldRecord.RDATA))\n                            throw new DnsWebServiceException(\"Cannot update record: the old record does not exists.\");\n\n                        if (authZone is SubDomainZone subDomainZone)\n                        {\n                            if (authZone.IsEmpty)\n                                _root.TryRemove(oldRecord.Name, out SubDomainZone _); //remove empty sub zone\n                            else\n                                subDomainZone.AutoUpdateState();\n                        }\n\n                        AuthZone newZone = GetOrAddSubDomainZone(zoneName, newRecord.Name);\n\n                        newZone.AddRecord(newRecord);\n\n                        if (newZone is SubDomainZone subDomainZone1)\n                            subDomainZone1.AutoUpdateState();\n                    }\n                    break;\n            }","sourceCodeStart":2339,"sourceCodeEnd":2375,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs#L2339-L2375","documentation":"Thrown by UpdateRecord in the default case branch (non-CNAME/DNAME/APP records) when oldRecord.Name differs from newRecord.Name AND authZone.DeleteRecord(oldRecord.Type, oldRecord.RDATA) returns false. This means the specific old record's RDATA could not be found for deletion during a name-move operation. Notably this throws DnsWebServiceException, not DnsServerException like the other UpdateRecord errors.","triggerScenarios":"Calling UpdateRecord where the old and new records have different names (moving a record to a new name), and the old record's exact RDATA does not match what is stored in the zone. The DeleteRecord(type, rdata) overload returns false when the RDATA doesn't match any stored record, triggering this exception.","commonSituations":"oldRecord was constructed from stale data and its RDATA no longer matches the zone's current record (e.g. TTL or RDATA content changed since the client fetched it); concurrent modification between fetch and update; RDATA comparison fails due to normalization differences (case in domain names within RDATA, whitespace).","solutions":["Re-fetch the current record from the zone before constructing oldRecord to ensure RDATA matches exactly.","Use a query to get the authoritative record, then pass that exact object as oldRecord.","If concurrent edits are expected, implement optimistic locking or retry the fetch-update cycle."],"exampleFix":"// before (oldRecord may have stale RDATA)\nauthZoneManager.UpdateRecord(\"example.com\", staleOldRecord, newRecord);\n\n// after (fetch fresh record first)\nvar currentRecords = authZoneManager.GetRecords(\"example.com\", oldRecord.Name, oldRecord.Type);\nif (currentRecords.Count == 0)\n    throw new InvalidOperationException(\"Old record not found; it may have been modified or deleted.\");\nauthZoneManager.UpdateRecord(\"example.com\", currentRecords[0], newRecord);","handlingStrategy":"validation","validationCode":"// fetch the current authoritative record before attempting a name-move update\nvar current = authZoneManager.GetRecords(zoneName, oldRecord.Name, oldRecord.Type);\nif (current.Count == 0 || !current[0].RDATA.Equals(oldRecord.RDATA))\n    throw new InvalidOperationException(\"Old record RDATA does not match current zone state.\");","typeGuard":"static bool RecordRdataMatches(DnsResourceRecord stored, DnsResourceRecord candidate)\n    => stored.Type == candidate.Type && stored.RDATA.Equals(candidate.RDATA);","tryCatchPattern":"try\n{\n    authZoneManager.UpdateRecord(zoneName, oldRecord, newRecord);\n}\ncatch (DnsWebServiceException ex) when (ex.Message.Contains(\"the old record does not exists\"))\n{\n    // RDATA was stale; re-fetch and retry\n    var fresh = authZoneManager.GetRecords(zoneName, oldRecord.Name, oldRecord.Type);\n    if (fresh.Count > 0)\n        authZoneManager.UpdateRecord(zoneName, fresh[0], newRecord);\n}","preventionTips":["Always fetch the current record from the zone before constructing oldRecord for a name-move update.","Pass the exact DnsResourceRecord object returned by the zone query as oldRecord.","Be aware this error uses DnsWebServiceException, not DnsServerException — catch accordingly."],"tags":["dns-records","zone-management","validation","record-update","stale-data"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}