TechnitiumSoftware/DnsServer · error · DnsServerException

Cannot convert to NSEC3: the zone must be signed with NSEC…

Error message

Cannot convert to NSEC3: the zone must be signed with NSEC for conversion.

What it means

Thrown by PrimaryZone.ConvertToNSec3 when the zone's DNSSEC status is not SignedWithNSEC. The library only permits converting a zone that is currently signed with plain NSEC into the NSEC3 variant; going straight from Unsigned to NSEC3 (or re-converting a zone already on NSEC3) is rejected so the existing NSEC chain can be cleanly disabled first.

Solutions

  1. If the zone is Unsigned, sign it first with NSEC (call SignZone with useNSec3=false), then call ConvertToNSec3.
  2. If the zone is already SignedWithNSEC3 and you want to change salt/iterations, call UpdateNSec3Parameters instead of ConvertToNSec3.
  3. Guard the call with a check on the zone's DnssecStatus property before invoking ConvertToNSec3.

Example fix

// before
zone.ConvertToNSec3(iterations: 2, saltLength: 8);

// after
if (zone.DnssecStatus == AuthZoneDnssecStatus.Unsigned)
    zone.SignZone(keys, dnsKeyTtl, useNSec3: false);
if (zone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC)
    zone.ConvertToNSec3(iterations: 2, saltLength: 8);
else if (zone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC3)
    zone.UpdateNSec3Parameters(iterations: 2, saltLength: 8);
Defensive patterns

Strategy: validation

Validate before calling

// Verify the zone is on NSEC before converting to NSEC3
if (zone.DnssecStatus != AuthZoneDnssecStatus.SignedWithNSEC)
{
    if (zone.DnssecStatus == AuthZoneDnssecStatus.Unsigned)
        zone.SignZone(keys, dnsKeyTtl, useNSec3: false);
    else if (zone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC3)
    {
        zone.UpdateNSec3Parameters(iterations, saltLength);
        return;
    }
}
zone.ConvertToNSec3(iterations, saltLength);

Type guard

static bool CanConvertToNSec3(ApexZone zone) =>
    zone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC;

Try / catch

try
{
    zone.ConvertToNSec3(iterations, saltLength);
}
catch (DnsServerException ex) when (ex.Message.Contains("must be signed with NSEC for conversion"))
{
    // sign with NSEC first, then retry; or route to UpdateNSec3Parameters
}

Prevention

When it happens

Trigger: Calling ConvertToNSec3(iterations, saltLength) on a zone whose DnssecStatus is Unsigned, or calling it again on a zone whose DnssecStatus is already SignedWithNSEC3.

Common situations: A developer enables DNSSEC signing and assumes NSEC3 is the default, calling ConvertToNSec3 without first calling SignZone with useNSec3=false. Or scripting a 're-sign as NSEC3' routine that fires against an already-NSEC3 zone after a reload.

Related errors


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

Appendix: source

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

                foreach (AuthZone zone in zones)
                {
                    if (!zone.IsEmpty)
                        nonEmptyZones.Add(zone);
                }

                EnableNSec(nonEmptyZones);

                _dnssecStatus = AuthZoneDnssecStatus.SignedWithNSEC;
            }

            TriggerNotify();
        }

        public void ConvertToNSec3(ushort iterations, byte saltLength)
        {
            if (_dnssecStatus != AuthZoneDnssecStatus.SignedWithNSEC)
                throw new DnsServerException("Cannot convert to NSEC3: the zone must be signed with NSEC for conversion.");

            if (iterations > 50)
                throw new ArgumentOutOfRangeException(nameof(iterations), "NSEC3 iterations valid range is 0-50");

            if (saltLength > 32)
                throw new ArgumentOutOfRangeException(nameof(saltLength), "NSEC3 salt length valid range is 0-32");

            lock (_dnssecUpdateLock)
            {
                IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetApexZoneWithSubDomainZones(_name);

                DisableNSec(zones);
                EnableNSec3(zones, iterations, saltLength);

                _dnssecStatus = AuthZoneDnssecStatus.SignedWithNSEC3;
            }

            TriggerNotify();

View on GitHub (pinned to d0484b6c1e)