TechnitiumSoftware/DnsServer · error · DnsServerException
Cannot update NSEC3 parameters: the zone must be signed with
Error message
Cannot update NSEC3 parameters: the zone must be signed with NSEC3 first.
What it means
Thrown by PrimaryZone.UpdateNSec3Parameters when the zone's DNSSEC status is not SignedWithNSEC3. Updating NSEC3 parameters only makes sense once an NSEC3 chain exists; calling it on an Unsigned zone or an NSEC-signed zone is rejected because there is no NSEC3PARAM record to rewrite.
Source
Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:750
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();
}
public void UpdateNSec3Parameters(ushort iterations, byte saltLength)
{
if (_dnssecStatus != AuthZoneDnssecStatus.SignedWithNSEC3)
throw new DnsServerException("Cannot update NSEC3 parameters: the zone must be signed with NSEC3 first.");
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);
DisableNSec3(zones);
//since zones were removed when disabling NSEC3; get updated non empty zones list
List<AuthZone> nonEmptyZones = new List<AuthZone>(zones.Count);
foreach (AuthZone zone in zones)
{View on GitHub (pinned to d0484b6c1e)
Solutions
- If the zone is Unsigned, sign it first (optionally with NSEC3) via SignZone before adjusting parameters.
- If the zone is SignedWithNSEC, call ConvertToNSec3 to establish NSEC3, then use UpdateNSec3Parameters for future changes.
- Guard the call by checking zone.DnssecStatus == SignedWithNSEC3.
Example fix
// before
zone.UpdateNSec3Parameters(iterations: 1, saltLength: 8);
// after
if (zone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC3)
zone.UpdateNSec3Parameters(iterations: 1, saltLength: 8);
else if (zone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC)
zone.ConvertToNSec3(iterations: 1, saltLength: 8); Defensive patterns
Strategy: validation
Validate before calling
// Only update NSEC3 parameters on an NSEC3-signed zone
if (zone.DnssecStatus != AuthZoneDnssecStatus.SignedWithNSEC3)
{
if (zone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC)
zone.ConvertToNSec3(iterations, saltLength);
else
zone.SignZone(keys, dnsKeyTtl, useNSec3: true, iterations, salt);
return;
}
zone.UpdateNSec3Parameters(iterations, saltLength); Type guard
static bool CanUpdateNSec3Parameters(ApexZone zone) =>
zone.DnssecStatus == AuthZoneDnssecStatus.SignedWithNSEC3; Try / catch
try
{
zone.UpdateNSec3Parameters(iterations, saltLength);
}
catch (DnsServerException ex) when (ex.Message.Contains("must be signed with NSEC3 first"))
{
// convert or sign with NSEC3 first, then retry
} Prevention
- Distinguish update (existing NSEC3) from convert (NSEC -> NSEC3) by checking DnssecStatus.
- Centralize DNSSEC-status checks in a helper used by every NSEC3 entry point.
When it happens
Trigger: Calling UpdateNSec3Parameters on a zone whose DnssecStatus is Unsigned or SignedWithNSEC.
Common situations: A maintenance script re-applies the same NSEC3 settings to all signed zones without checking which variant each one uses; an NSEC-signed zone hits this path.
Related errors
- Cannot convert to NSEC3: the zone must be signed with NSEC f
- NSEC3 salt length valid range is 0-32
- NSEC3 iterations valid range is 0-50
- The primary zone must be signed.
- The zone must be signed.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/d3489a53b025a529.
Report an issue: GitHub.