TechnitiumSoftware/DnsServer · error · DnsServerException

Cannot publish DNSKEY: the key is already published.

Error message

Cannot publish DNSKEY: the key is already published.

What it means

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.

Source

Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:1143

                    }
                }
            }

            if (generatedPrivateKeys.Count == 0)
                throw new DnsServerException("Cannot publish DNSKEY: no generated private keys were found.");

            IReadOnlyList<DnsResourceRecord> dnsKeyRecords = _entries.AddOrUpdate(DnsResourceRecordType.DNSKEY, delegate (DnsResourceRecordType key)
            {
                return newDnsKeyRecords;
            },
            delegate (DnsResourceRecordType key, IReadOnlyList<DnsResourceRecord> existingRecords)
            {
                foreach (DnsResourceRecord existingRecord in existingRecords)
                {
                    foreach (DnsResourceRecord newDnsKeyRecord in newDnsKeyRecords)
                    {
                        if (existingRecord.Equals(newDnsKeyRecord))
                            throw new DnsServerException("Cannot publish DNSKEY: the key is already published.");
                    }
                }

                List<DnsResourceRecord> dnsKeyRecords = new List<DnsResourceRecord>(existingRecords.Count + newDnsKeyRecords.Count);

                dnsKeyRecords.AddRange(existingRecords);
                dnsKeyRecords.AddRange(newDnsKeyRecords);

                return dnsKeyRecords;
            });

            //update private key state before signing
            uint propagationDelay = GetPropagationDelay();

            foreach (DnssecPrivateKey privateKey in generatedPrivateKeys)
                privateKey.SetState(DnssecPrivateKeyState.Published, dnsKeyTtl + propagationDelay);

            List<DnsResourceRecord> addedRecords = new List<DnsResourceRecord>();

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Before publishing, compare each Generated key's DNSKEY against the zone's existing DNSKEY records and skip duplicates.
  2. If duplicates exist from a bad restore, remove the stale DNSKEY records first, then publish.
  3. Make publish idempotent: catch the 'already published' condition and treat it as success for that key.

Example fix

// before
zone.PublishAllGeneratedKeys();

// after
var existingDnsKeys = zone.GetRecords(DnsResourceRecordType.DNSKEY) ?? Array.Empty<DnsResourceRecord>();
bool hasUnpublished = zone.DnssecPrivateKeys
    .Where(k => k.State == DnssecPrivateKeyState.Generated)
    .Any(k => !existingDnsKeys.Any(r => r.Equals(new DnsResourceRecord(zone.Name, DnsResourceRecordType.DNSKEY, DnsClass.IN, ttl, k.DnsKey))));
if (hasUnpublished)
    zone.PublishAllGeneratedKeys();
Defensive patterns

Strategy: validation

Validate before calling

// Skip publishing keys whose DNSKEY is already in the zone
var existing = (zone.GetRecords(DnsResourceRecordType.DNSKEY) ?? Array.Empty<DnsResourceRecord>()).ToList();
var toPublish = zone.DnssecPrivateKeys
    .Where(k => k.State == DnssecPrivateKeyState.Generated)
    .Where(k => !existing.Any(r => r.RDATA.Equals(k.DnsKey)))
    .ToList();
if (toPublish.Count > 0)
    zone.PublishAllGeneratedKeys();

Type guard

static bool DnsKeyAlreadyPublished(IEnumerable<DnsResourceRecord> existing, DnssecPrivateKey key) =>
    existing.Any(r => r.RDATA.Equals(key.DnsKey));

Try / catch

try
{
    zone.PublishAllGeneratedKeys();
}
catch (DnsServerException ex) when (ex.Message.Contains("the key is already published"))
{
    // one or more keys are already in the DNSKEY set; remove stale Generated entries or skip
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13). Data as JSON: /api/errors/e1bfbe6582db63e5. Report an issue: GitHub.