TechnitiumSoftware/DnsServer · error · DnsServerException

The primary zone must be signed.

Error message

The primary zone must be signed.

What it means

Thrown by GenerateAndAddPrivateKey when the zone's DNSSEC status is Unsigned. Private keys can only live on a signed zone because their DNSKEY material has nowhere to be published otherwise; the guard blocks creating keys against an unsigned zone.

Source

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

            {
                deletedRecords.AddRange(zone.RemoveNSec3RecordsWithRRSig());

                if (zone is SubDomainZone subDomainZone)
                {
                    if (zone.IsEmpty)
                        _dnsServer.AuthZoneManager.RemoveSubDomainZone(zone.Name); //remove empty sub zone
                    else
                        subDomainZone.AutoUpdateState();
                }
            }

            CommitAndIncrementSerial(deletedRecords);
        }

        public DnssecPrivateKey GenerateAndAddPrivateKey(DnssecPrivateKeyType keyType, DnssecAlgorithm algorithm, ushort rolloverDays, int keySize = -1)
        {
            if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
                throw new DnsServerException("The primary zone must be signed.");

            int i = 0;
            while (i++ < 5)
            {
                DnssecPrivateKey privateKey = DnssecPrivateKey.Create(algorithm, keyType, keySize);
                privateKey.RolloverDays = rolloverDays;

                lock (_dnssecPrivateKeys)
                {
                    if (_dnssecPrivateKeys.TryAdd(privateKey.KeyTag, privateKey))
                        return privateKey;
                }
            }

            throw new DnsServerException("Failed to add private key: key tag collision. Please try again.");
        }

        public void AddPrivateKey(DnssecPrivateKey privateKey)

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Sign the zone first with SignZone, then call GenerateAndAddPrivateKey.
  2. If you have keys you want to import, sign the zone with those keys in one SignZone call instead.
  3. Guard the call with a DnssecStatus != Unsigned check.

Example fix

// before
var key = zone.GenerateAndAddPrivateKey(DnssecPrivateKeyType.KeySigningKey, DnssecAlgorithm.ECDSAP256SHA256, 365);

// after
if (zone.DnssecStatus == AuthZoneDnssecStatus.Unsigned)
    throw new InvalidOperationException("Sign the zone before generating keys.");
var key = zone.GenerateAndAddPrivateKey(DnssecPrivateKeyType.KeySigningKey, DnssecAlgorithm.ECDSAP256SHA256, 365);
Defensive patterns

Strategy: validation

Validate before calling

// Only generate keys on a signed zone
if (zone.DnssecStatus == AuthZoneDnssecStatus.Unsigned)
    zone.SignZone(initialKeys, dnsKeyTtl, useNSec3: false);
var key = zone.GenerateAndAddPrivateKey(keyType, algorithm, rolloverDays);

Type guard

static bool IsZoneSignedForKeys(ApexZone zone) =>
    zone.DnssecStatus != AuthZoneDnssecStatus.Unsigned;

Try / catch

try
{
    key = zone.GenerateAndAddPrivateKey(keyType, algorithm, rolloverDays);
}
catch (DnsServerException ex) when (ex.Message == "The primary zone must be signed.")
{
    zone.SignZone(initialKeys, dnsKeyTtl, useNSec3: false);
    key = zone.GenerateAndAddPrivateKey(keyType, algorithm, rolloverDays);
}

Prevention

When it happens

Trigger: Calling GenerateAndAddPrivateKey(keyType, algorithm, rolloverDays) on a zone whose DnssecStatus is Unsigned.

Common situations: Provisioning keys before signing; an orchestration script that adds keys then signs, in the wrong order.

Related errors


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