{"record":{"id":"bc8f862c7e67a1f1","repo":"TechnitiumSoftware/DnsServer","slug":"cannot-update-record-the-record-does-not-exists-t-bc8f86","errorCode":null,"errorMessage":"Cannot update record: the record does not exists to be updated.","messagePattern":"Cannot update record: the record does not exists to be updated\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs","lineNumber":242,"sourceCode":"                case DnsResourceRecordType.DNSKEY:\n                case DnsResourceRecordType.RRSIG:\n                case DnsResourceRecordType.NSEC:\n                case DnsResourceRecordType.NSEC3PARAM:\n                case DnsResourceRecordType.NSEC3:\n                    throw new InvalidOperationException(\"Cannot update DNSSEC records.\");\n\n                default:\n                    if (oldRecord.Type != newRecord.Type)\n                        throw new InvalidOperationException(\"Old and new record types do not match.\");\n\n                    if ((_primaryZone.DnssecStatus != AuthZoneDnssecStatus.Unsigned) && newRecord.GetAuthGenericRecordInfo().Disabled)\n                        throw new DnsServerException(\"Cannot update record: disabling records in a signed zones is not supported.\");\n\n                    if (newRecord.OriginalTtlValue > _primaryZone.GetZoneSoaExpire())\n                        throw new DnsServerException(\"Cannot update record: TTL cannot be greater than SOA EXPIRE.\");\n\n                    if (!TryDeleteRecord(oldRecord.Type, oldRecord.RDATA, out DnsResourceRecord deletedRecord))\n                        throw new InvalidOperationException(\"Cannot update record: the record does not exists to be updated.\");\n\n                    AddRecord(newRecord, out IReadOnlyList<DnsResourceRecord> addedRecords, out IReadOnlyList<DnsResourceRecord> deletedRecords);\n\n                    List<DnsResourceRecord> allDeletedRecords = new List<DnsResourceRecord>(deletedRecords.Count + 1);\n                    allDeletedRecords.Add(deletedRecord);\n                    allDeletedRecords.AddRange(deletedRecords);\n\n                    _primaryZone.CommitAndIncrementSerial(allDeletedRecords, addedRecords);\n\n                    if (_primaryZone.DnssecStatus != AuthZoneDnssecStatus.Unsigned)\n                        _primaryZone.UpdateDnssecRecordsFor(this, oldRecord.Type);\n\n                    _primaryZone.TriggerNotify();\n                    break;\n            }\n        }\n\n        #endregion","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimarySubDomainZone.cs#L224-L260","documentation":"Thrown by PrimarySubDomainZone.UpdateRecord when TryDeleteRecord(oldRecord.Type, oldRecord.RDATA) returns false — i.e., the exact old record is not present in the zone. UpdateRecord is a delete-then-add atomic pair, so the old record must exist verbatim. The guard raises InvalidOperationException ('does not exists' is a verbatim source typo) before adding the new record, leaving the zone unchanged.","triggerScenarios":"zone.UpdateRecord(old, new) where 'old' was already deleted, never existed, or whose RDATA does not byte-match the stored RRset.","commonSituations":"Stale 'old' snapshot read before a concurrent edit; race where another client deleted the record; comparing records by partial fields rather than full RDATA.","solutions":["Re-read the current record from the zone and use it as 'old' before updating.","Use optimistic-concurrency: if the update fails with 'does not exist', reload and retry or report not-found.","Ensure the old record's RDATA matches the stored record exactly (case, wire format)."],"exampleFix":"// before\nzone.UpdateRecord(staleOld, newRecord); // throws if gone\n\n// after\nif (!zone.TryGetRecords(oldRecord.Type, out var current)\n    || !current.Any(r => r.RDATA.SequenceEqual(oldRecord.RDATA)))\n    return; // record already gone; nothing to update\nzone.UpdateRecord(oldRecord, newRecord);","handlingStrategy":"validation","validationCode":"if (!zone.TryGetRecords(oldRecord.Type, out var rrset)\n    || !rrset.Any(r => r.RDATA.SequenceEqual(oldRecord.RDATA)))\n    return; // already gone\nzone.UpdateRecord(oldRecord, newRecord);","typeGuard":"static bool RecordExists(IReadOnlyList<DnsResourceRecord> rrset, DnsResourceRecord oldR) =>\n    rrset.Any(r => r.RDATA.SequenceEqual(oldR.RDATA));","tryCatchPattern":"try { zone.UpdateRecord(oldRecord, newRecord); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"does not exists\"))\n{ /* stale snapshot: reload and retry, or treat as no-op */ }","preventionTips":["Reload the old record immediately before UpdateRecord under contention.","Compare records by full RDATA, not partial fields.","Handle 'does not exist' as a recoverable optimistic-concurrency signal."],"tags":["csharp","dns","zone-management","concurrency","validation","technitium-dns"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}