TechnitiumSoftware/DnsServer · error · DnsServerException
Cannot sign zone: the zone is already signed.
Error message
Cannot sign zone: the zone is already signed.
What it means
Thrown by the collection overload PrimaryZone.SignZone(...) when _dnssecStatus != AuthZoneDnssecStatus.Unsigned. A zone can only be signed from the Unsigned state; re-signing a zone that is already NSEC/NSEC3-signed must go through re-sign/key-roll paths. The guard raises DnsServerException as the very first validation.
Source
Thrown at DnsServerCore/Dns/Zones/PrimaryZone.cs:478
if (saltLength > 0)
{
salt = new byte[saltLength];
RandomNumberGenerator.Fill(salt);
}
else
{
salt = [];
}
}
SignZone([kskPrivateKey, zskPrivateKey], dnsKeyTtl, useNSec3, iterations, salt);
}
public void SignZone(IReadOnlyCollection<DnssecPrivateKey> dnssecPrivateKeys, uint dnsKeyTtl, bool useNSec3, ushort iterations = 0, byte[] salt = null)
{
//do validations
if (_dnssecStatus != AuthZoneDnssecStatus.Unsigned)
throw new DnsServerException("Cannot sign zone: the zone is already signed.");
if (useNSec3)
{
if (iterations > 50)
throw new ArgumentOutOfRangeException(nameof(iterations), "NSEC3 iterations valid range is 0-50");
if (salt.Length > 32)
throw new ArgumentOutOfRangeException(nameof(salt), "NSEC3 salt length valid range is 0-32");
}
bool foundKsk = false;
bool foundZsk = false;
foreach (DnssecPrivateKey dnssecPrivateKey in dnssecPrivateKeys)
{
switch (dnssecPrivateKey.KeyType)
{
case DnssecPrivateKeyType.KeySigningKey:View on GitHub (pinned to d0484b6c1e)
Solutions
- Check zone.DnssecStatus == Unsigned before calling SignZone.
- If already signed and you want different params, call UnsignZone() first, then SignZone.
- Serialize sign/unsign operations behind a lock to avoid concurrent double-sign.
Example fix
// before
zone.SignZone(keys, ttl, useNSec3: true);
// after
if (zone.DnssecStatus != AuthZoneDnssecStatus.Unsigned)
zone.UnsignZone();
zone.SignZone(keys, ttl, useNSec3: true); Defensive patterns
Strategy: try-catch
Validate before calling
if (zone.DnssecStatus != AuthZoneDnssecStatus.Unsigned)
zone.UnsignZone();
zone.SignZone(keys, ttl, useNSec3); Type guard
static bool CanSign(AuthZone z) => z.DnssecStatus == AuthZoneDnssecStatus.Unsigned;
Try / catch
try { zone.SignZone(keys, ttl, useNSec3); }
catch (DnsServerException ex) when (ex.Message.Contains("already signed"))
{ /* concurrent signer won: refresh status, no-op or unsign+retry per intent */ } Prevention
- Check DnssecStatus == Unsigned before signing.
- Serialize sign/unsign behind a lock to avoid races.
- To change sign params, UnsignZone then SignZone.
When it happens
Trigger: Calling zone.SignZone(...) when the zone is already SignedWithNSEC or SignedWithNSEC3 — e.g., signing twice, or signing after a failed sign that left partial state under a race.
Common situations: Retry loop that re-invokes SignZone after a transient failure; UI 'Sign' button pressed twice; concurrent sign requests.
Related errors
- Cannot unsign zone: the is zone not signed.
- Cannot delete DNSSEC records.
- Cannot update DNSSEC records.
- Cannot update record: disabling records in a signed zones is
- Cannot update record: the record does not exists to be updat
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/f765490d2e90e4ed.
Report an issue: GitHub.