TechnitiumSoftware/DnsServer · error · InvalidOperationException

Zone must be a primary, secondary, or forwarder zone.

Error message

Zone must be a primary, secondary, or forwarder zone.

What it means

Thrown by QueryZoneTransferRecords when the zone exists but has a SOA record count != 1. Full zone transfer (AXFR) requires exactly one SOA record at the apex. Zones without a proper SOA (e.g. Stub zones, Catalog zones, or zones in a corrupted/incomplete state) cannot be transferred. The error message lists the supported types: primary, secondary, forwarder.

Source

Thrown at DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs:2476

                        subDomainZone.AutoUpdateState();
                }
            }
        }

        #endregion

        #region zone transfer / import

        public IReadOnlyList<DnsResourceRecord> QueryZoneTransferRecords(string zoneName)
        {
            AuthZoneInfo zoneInfo = GetAuthZoneInfo(zoneName);
            if (zoneInfo is null)
                throw new InvalidOperationException("Zone was not found: " + zoneName);

            //primary, secondary, and forwarder zones support zone transfer
            IReadOnlyList<DnsResourceRecord> soaRecords = zoneInfo.ApexZone.GetRecords(DnsResourceRecordType.SOA);
            if (soaRecords.Count != 1)
                throw new InvalidOperationException("Zone must be a primary, secondary, or forwarder zone.");

            DnsResourceRecord soaRecord = soaRecords[0];

            List<DnsResourceRecord> records = new List<DnsResourceRecord>();
            ListAllZoneRecords(zoneName, records);

            List<DnsResourceRecord> xfrRecords = new List<DnsResourceRecord>(records.Count + 1);

            //start message
            xfrRecords.Add(soaRecord);

            foreach (DnsResourceRecord record in records)
            {
                GenericRecordInfo authRecordInfo = record.GetAuthGenericRecordInfo();
                if (authRecordInfo.Disabled)
                    continue;

                switch (record.Type)

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Check the zone type before transferring: only Primary, Secondary, and Forwarder zones support AXFR.
  2. Verify the zone has exactly one SOA record by querying apex SOA records.
  3. If the zone is a stub or catalog, do not attempt standard zone transfer.
  4. Repair the zone file if SOA is missing or duplicated.

Example fix

// before
var xfrRecords = authZoneManager.QueryZoneTransferRecords(zoneName);

// after
AuthZoneInfo info = authZoneManager.GetAuthZoneInfo(zoneName);
if (info is null)
    throw new InvalidOperationException("Zone not found.");
if (info.Type != AuthZoneType.Primary && info.Type != AuthZoneType.Secondary && info.Type != AuthZoneType.Forwarder)
    throw new InvalidOperationException($"Zone type '{info.Type}' does not support AXFR.");
var xfrRecords = authZoneManager.QueryZoneTransferRecords(zoneName);
Defensive patterns

Strategy: validation

Validate before calling

AuthZoneInfo info = authZoneManager.GetAuthZoneInfo(zoneName);
if (info is null)
    throw new InvalidOperationException("Zone not found.");
if (info.Type != AuthZoneType.Primary && info.Type != AuthZoneType.Secondary && info.Type != AuthZoneType.Forwarder)
    throw new InvalidOperationException($"Zone type '{info.Type}' does not support AXFR.");

Type guard

static bool ZoneSupportsAxfr(AuthZoneManager mgr, string zoneName)
{
    AuthZoneInfo info = mgr.GetAuthZoneInfo(zoneName);
    if (info is null) return false;
    return info.Type is AuthZoneType.Primary or AuthZoneType.Secondary or AuthZoneType.Forwarder;
}

Try / catch

try
{
    var records = authZoneManager.QueryZoneTransferRecords(zoneName);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("primary, secondary, or forwarder"))
{
    logger.LogWarning("AXFR not supported for zone '{Zone}': wrong zone type.", zoneName);
}

Prevention

When it happens

Trigger: Calling QueryZoneTransferRecords on a Stub zone (which has NS records but no SOA), a Catalog zone, or a zone whose SOA record is missing or duplicated due to corruption. The zoneInfo is non-null (passes the null check) but zoneInfo.ApexZone.GetRecords(SOA).Count is 0 or >1.

Common situations: Misconfigured zone transfer ACL allowing transfer of stub zones; zone file corruption causing missing or duplicate SOA; catalog zone being queried for AXFR (catalogs use a different transfer mechanism); zone in a partially-loaded state.

Related errors


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