TechnitiumSoftware/DnsServer · error · DnsServerException

Invalid IXFR/AXFR response was received.

Error message

Invalid IXFR/AXFR response was received.

What it means

Thrown by SyncIncrementalZoneTransferRecords when the received IXFR/AXFR response fails the same structural validation as SyncZoneTransferRecords: fewer than 2 records, first record not SOA, name mismatch, or start/end SOA not equal. This is the entry point for processing incoming incremental transfer data; it validates the envelope before deciding whether the payload is IXFR or AXFR format.

Source

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

                if (zone.Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase))
                    zone.SyncRecords(latestEntries.Value);
                else if ((zone is SubDomainZone subDomainZone) && subDomainZone.AuthoritativeZone.Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase))
                    zone.SyncRecords(latestEntries.Value);
            }

            if (!_root.TryGet(zoneName, out ApexZone apexZone))
                throw new InvalidOperationException();

            apexZone.UpdateDnssecStatus();

            SaveZoneFile(apexZone.Name);
        }

        public IReadOnlyList<DnsResourceRecord> SyncIncrementalZoneTransferRecords(string zoneName, IReadOnlyList<DnsResourceRecord> xfrRecords)
        {
            if ((xfrRecords.Count < 2) || (xfrRecords[0].Type != DnsResourceRecordType.SOA) || !xfrRecords[0].Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase) || !xfrRecords[xfrRecords.Count - 1].Equals(xfrRecords[0]))
                throw new DnsServerException("Invalid IXFR/AXFR response was received.");

            if ((xfrRecords.Count < 4) || (xfrRecords[1].Type != DnsResourceRecordType.SOA))
            {
                //received AXFR response
                SyncZoneTransferRecords(zoneName, xfrRecords);
                return Array.Empty<DnsResourceRecord>();
            }

            if (!_root.TryGet(zoneName, out ApexZone apexZone))
                throw new InvalidOperationException("No such zone was found: " + zoneName);

            IReadOnlyList<DnsResourceRecord> soaRecords = apexZone.GetRecords(DnsResourceRecordType.SOA);
            if (soaRecords.Count != 1)
                throw new InvalidOperationException("No authoritative zone was found: " + zoneName);

            //process IXFR response
            DnsResourceRecord currentSoaRecord = soaRecords[0];
            DnsSOARecordData currentSoa = currentSoaRecord.RDATA as DnsSOARecordData;

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Validate xfrRecords.Count >= 2, first is SOA, first.Name matches zoneName, first.Equals(last) before calling SyncIncrementalZoneTransferRecords.
  2. If validation fails, fall back to requesting a full AXFR from the primary.
  3. Check the remote primary server's health and DNS software version compatibility.
  4. Verify network reliability for the TCP connection carrying the transfer.

Example fix

// before
var deleted = authZoneManager.SyncIncrementalZoneTransferRecords(zoneName, xfrRecords);

// after
bool IsValidEnvelope(IReadOnlyList<DnsResourceRecord> records, string zone)
    => records.Count >= 2
       && records[0].Type == DnsResourceRecordType.SOA
       && records[0].Name.Equals(zone, StringComparison.OrdinalIgnoreCase)
       && records[^1].Equals(records[0]);

if (!IsValidEnvelope(xfrRecords, zoneName))
{
    _logger.LogWarning("Malformed IXFR/AXFR for '{Zone}'; falling back to full AXFR.", zoneName);
    xfrRecords = await dnsClient.QueryZoneTransferAsync(zoneName);
    authZoneManager.SyncZoneTransferRecords(zoneName, xfrRecords);
    return Array.Empty<DnsResourceRecord>();
}
var deleted = authZoneManager.SyncIncrementalZoneTransferRecords(zoneName, xfrRecords);
Defensive patterns

Strategy: validation

Validate before calling

static bool IsValidXfrResponse(string zoneName, IReadOnlyList<DnsResourceRecord> xfrRecords)
{
    return xfrRecords.Count >= 2
        && xfrRecords[0].Type == DnsResourceRecordType.SOA
        && xfrRecords[0].Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase)
        && xfrRecords[^1].Equals(xfrRecords[0]);
}

if (!IsValidXfrResponse(zoneName, xfrRecords))
    throw new InvalidOperationException("Invalid IXFR/AXFR response structure.");

Type guard

static bool IsValidXfrEnvelope(IReadOnlyList<DnsResourceRecord> records, string zoneName)
    => records.Count >= 2
       && records[0].Type == DnsResourceRecordType.SOA
       && records[0].Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase)
       && records[^1].Equals(records[0]);

Try / catch

try
{
    var deleted = authZoneManager.SyncIncrementalZoneTransferRecords(zoneName, xfrRecords);
}
catch (DnsServerException ex) when (ex.Message.Contains("Invalid IXFR/AXFR response"))
{
    logger.LogWarning("IXFR/AXFR sync failed for '{Zone}'; falling back to full AXFR.", zoneName);
    xfrRecords = await dnsClient.QueryZoneTransferAsync(zoneName);
    authZoneManager.SyncZoneTransferRecords(zoneName, xfrRecords);
}

Prevention

When it happens

Trigger: Calling SyncIncrementalZoneTransferRecords(zoneName, xfrRecords) with a malformed response. If the response has fewer than 4 records or the second record is not SOA, it falls through to SyncZoneTransferRecords (AXFR path). The validation at line 2687 catches the most basic structural problems before that branching logic.

Common situations: Remote primary returns a truncated or empty response; TCP connection dropped mid-transfer producing an incomplete record list; primary server sends unexpected record types; zone name mismatch between the transfer request and the received data; incompatible DNS server implementation.

Related errors


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