TechnitiumSoftware/DnsServer · error · DnsServerException

Cannot unsign zone: the is zone not signed.

Error message

Cannot unsign zone: the is zone not signed.

What it means

Thrown by PrimaryZone.UnsignZone when _dnssecStatus == AuthZoneDnssecStatus.Unsigned — i.e., the zone is not signed, so there is nothing to unsign. The guard raises DnsServerException before gathering the apex/sub-domain zone list. (Message text 'the is zone not signed' is a verbatim source wording.)

Source

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

                foreach (KeyValuePair<string, Dictionary<DnsResourceRecordType, List<DnsResourceRecord>>> deletedRecordGroup in deletedRecordGroups)
                {
                    AuthZone zone = _dnsServer.AuthZoneManager.GetAuthZone(_name, deletedRecordGroup.Key);

                    foreach (KeyValuePair<DnsResourceRecordType, List<DnsResourceRecord>> deletedRecordEntry in deletedRecordGroup.Value)
                    {
                        foreach (DnsResourceRecord deletedRecord in deletedRecordEntry.Value)
                            zone.AddRecord(deletedRecord, out _, out _);
                    }
                }

                throw;
            }
        }

        public void UnsignZone()
        {
            if (_dnssecStatus == AuthZoneDnssecStatus.Unsigned)
                throw new DnsServerException("Cannot unsign zone: the is zone not signed.");

            List<DnsResourceRecord> deletedRecords = new List<DnsResourceRecord>();
            IReadOnlyList<AuthZone> zones = _dnsServer.AuthZoneManager.GetApexZoneWithSubDomainZones(_name);

            foreach (AuthZone zone in zones)
            {
                deletedRecords.AddRange(zone.RemoveAllDnssecRecords());

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

            Timer dnssecTimer = _dnssecTimer;

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Check zone.DnssecStatus != Unsigned before calling UnsignZone.
  2. Treat 'already unsigned' as a no-op in the caller rather than an error.
  3. Guard concurrent unsign operations to avoid racing into Unsigned state.

Example fix

// before
zone.UnsignZone(); // may throw if unsigned

// after
if (zone.DnssecStatus != AuthZoneDnssecStatus.Unsigned)
    zone.UnsignZone();
Defensive patterns

Strategy: try-catch

Validate before calling

if (zone.DnssecStatus != AuthZoneDnssecStatus.Unsigned)
    zone.UnsignZone();

Type guard

static bool CanUnsign(AuthZone z) => z.DnssecStatus != AuthZoneDnssecStatus.Unsigned;

Try / catch

try { zone.UnsignZone(); }
catch (DnsServerException ex) when (ex.Message.Contains("not signed"))
{ /* already unsigned: treat as no-op */ }

Prevention

When it happens

Trigger: Calling zone.UnsignZone() on an already-unsigned primary zone; double-unsign after a previous call; unsign after a failed sign that rolled back to Unsigned.

Common situations: UI 'Unsign' pressed on a zone that was never signed; automation that unsigns defensively without checking state.

Related errors


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