{"record":{"id":"e7616cebd913c191","repo":"TechnitiumSoftware/DnsServer","slug":"cannot-update-dnssec-records-e7616c","errorCode":null,"errorMessage":"Cannot update DNSSEC records.","messagePattern":"Cannot update DNSSEC records\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Zones/PrimaryZone.cs","lineNumber":2752,"sourceCode":"                    }\n\n                    return false;\n            }\n        }\n\n        public override void UpdateRecord(DnsResourceRecord oldRecord, DnsResourceRecord newRecord)\n        {\n            switch (oldRecord.Type)\n            {\n                case DnsResourceRecordType.SOA:\n                    throw new InvalidOperationException(\"Cannot update record: use SetRecords() for \" + oldRecord.Type.ToString() + \" record\");\n\n                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 ((_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 > 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 DnsServerException(\"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);","sourceCodeStart":2734,"sourceCodeEnd":2770,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimaryZone.cs#L2734-L2770","documentation":"Thrown by PrimaryZone.UpdateRecord when oldRecord.Type is a DNSSEC type (DNSKEY, RRSIG, NSEC, NSEC3PARAM, NSEC3). DNSSEC records are regenerated by the signing engine, so updating them manually is rejected as InvalidOperationException. Mirrors the protections on Add/Delete.","triggerScenarios":"Calling zone.UpdateRecord(oldRecord, newRecord) where oldRecord.Type is a DNSSEC record type.","commonSituations":"Generic record-editing pipelines that handle all types uniformly; key rollover scripts that try to swap a DNSKEY via UpdateRecord.","solutions":["Exclude DNSSEC types from UpdateRecord; trigger re-signing instead.","Branch on type so DNSSEC records are never passed to UpdateRecord.","For key rollover, use the zone's DNSSEC private-key management API rather than record mutation."],"exampleFix":"// before\nzone.UpdateRecord(oldRecord, newRecord);\n\n// after\nif (IsDnssecType(oldRecord.Type))\n    throw new InvalidOperationException(\"DNSSEC records are managed by signing.\");\nzone.UpdateRecord(oldRecord, newRecord);","handlingStrategy":"type-guard","validationCode":"if (IsDnssecType(oldRecord.Type))\n    throw new InvalidOperationException(\"DNSSEC records are managed by signing.\");\nzone.UpdateRecord(oldRecord, newRecord);","typeGuard":"static bool IsDnssecType(DnsResourceRecordType t) =>\n    t == DnsResourceRecordType.DNSKEY || t == DnsResourceRecordType.RRSIG ||\n    t == DnsResourceRecordType.NSEC || t == DnsResourceRecordType.NSEC3PARAM ||\n    t == DnsResourceRecordType.NSEC3;","tryCatchPattern":"null","preventionTips":["Keep DNSSEC records out of all generic update pipelines.","Trigger re-signing to change DNSSEC material."],"tags":["dns","primary-zone","dnssec","immutable-record","update"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}