{"record":{"id":"e1bfbe6582db63e5","repo":"TechnitiumSoftware/DnsServer","slug":"cannot-publish-dnskey-the-key-is-already-publishe","errorCode":null,"errorMessage":"Cannot publish DNSKEY: the key is already published.","messagePattern":"Cannot publish DNSKEY: the key is already published\\.","errorType":"exception","errorClass":"DnsServerException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Zones/PrimaryZone.cs","lineNumber":1143,"sourceCode":"                    }\n                }\n            }\n\n            if (generatedPrivateKeys.Count == 0)\n                throw new DnsServerException(\"Cannot publish DNSKEY: no generated private keys were found.\");\n\n            IReadOnlyList<DnsResourceRecord> dnsKeyRecords = _entries.AddOrUpdate(DnsResourceRecordType.DNSKEY, delegate (DnsResourceRecordType key)\n            {\n                return newDnsKeyRecords;\n            },\n            delegate (DnsResourceRecordType key, IReadOnlyList<DnsResourceRecord> existingRecords)\n            {\n                foreach (DnsResourceRecord existingRecord in existingRecords)\n                {\n                    foreach (DnsResourceRecord newDnsKeyRecord in newDnsKeyRecords)\n                    {\n                        if (existingRecord.Equals(newDnsKeyRecord))\n                            throw new DnsServerException(\"Cannot publish DNSKEY: the key is already published.\");\n                    }\n                }\n\n                List<DnsResourceRecord> dnsKeyRecords = new List<DnsResourceRecord>(existingRecords.Count + newDnsKeyRecords.Count);\n\n                dnsKeyRecords.AddRange(existingRecords);\n                dnsKeyRecords.AddRange(newDnsKeyRecords);\n\n                return dnsKeyRecords;\n            });\n\n            //update private key state before signing\n            uint propagationDelay = GetPropagationDelay();\n\n            foreach (DnssecPrivateKey privateKey in generatedPrivateKeys)\n                privateKey.SetState(DnssecPrivateKeyState.Published, dnsKeyTtl + propagationDelay);\n\n            List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();","sourceCodeStart":1125,"sourceCodeEnd":1161,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimaryZone.cs#L1125-L1161","documentation":"Thrown inside the AddOrUpdate update delegate of PublishAllGeneratedKeys when a DNSKEY record being published already equals one present in the zone. The method merges new DNSKEY records with existing ones; an exact-match record means the key is already published, so it refuses rather than creating a duplicate RRset entry.","triggerScenarios":"Calling PublishAllGeneratedKeys when one or more Generated keys' DNSKEY records are byte-for-byte identical to DNSKEY records already in the zone (e.g. re-publishing after a partial publish or a reload that left stale DNSKEY records).","commonSituations":"A crash between marking a key Published and committing the DNSKEY set; importing a zone that already carried the DNSKEY; calling publish against a key whose DNSKEY was restored from backup.","solutions":["Before publishing, compare each Generated key's DNSKEY against the zone's existing DNSKEY records and skip duplicates.","If duplicates exist from a bad restore, remove the stale DNSKEY records first, then publish.","Make publish idempotent: catch the 'already published' condition and treat it as success for that key."],"exampleFix":"// before\nzone.PublishAllGeneratedKeys();\n\n// after\nvar existingDnsKeys = zone.GetRecords(DnsResourceRecordType.DNSKEY) ?? Array.Empty<DnsResourceRecord>();\nbool hasUnpublished = zone.DnssecPrivateKeys\n    .Where(k => k.State == DnssecPrivateKeyState.Generated)\n    .Any(k => !existingDnsKeys.Any(r => r.Equals(new DnsResourceRecord(zone.Name, DnsResourceRecordType.DNSKEY, DnsClass.IN, ttl, k.DnsKey))));\nif (hasUnpublished)\n    zone.PublishAllGeneratedKeys();","handlingStrategy":"validation","validationCode":"// Skip publishing keys whose DNSKEY is already in the zone\nvar existing = (zone.GetRecords(DnsResourceRecordType.DNSKEY) ?? Array.Empty<DnsResourceRecord>()).ToList();\nvar toPublish = zone.DnssecPrivateKeys\n    .Where(k => k.State == DnssecPrivateKeyState.Generated)\n    .Where(k => !existing.Any(r => r.RDATA.Equals(k.DnsKey)))\n    .ToList();\nif (toPublish.Count > 0)\n    zone.PublishAllGeneratedKeys();","typeGuard":"static bool DnsKeyAlreadyPublished(IEnumerable<DnsResourceRecord> existing, DnssecPrivateKey key) =>\n    existing.Any(r => r.RDATA.Equals(key.DnsKey));","tryCatchPattern":"try\n{\n    zone.PublishAllGeneratedKeys();\n}\ncatch (DnsServerException ex) when (ex.Message.Contains(\"the key is already published\"))\n{\n    // one or more keys are already in the DNSKEY set; remove stale Generated entries or skip\n}","preventionTips":["Before publishing, diff Generated keys' DNSKEY records against the zone's existing DNSKEY set.","If a partial publish left stale state, remove the duplicate DNSKEY records before retrying."],"tags":["dnssec","private-key","dnskey","validation","duplicate","csharp"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}