{"record":{"id":"a5808506c9585168","repo":"TechnitiumSoftware/DnsServer","slug":"current-soa-serial-does-not-match-with-the-ixfr-di","errorCode":null,"errorMessage":"Current SOA serial does not match with the IXFR difference sequence deleted SOA.","messagePattern":"Current SOA serial does not match with the IXFR difference sequence deleted SOA\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs","lineNumber":2823,"sourceCode":"                        {\n                            switch (record.Type)\n                            {\n                                case DnsResourceRecordType.A:\n                                case DnsResourceRecordType.AAAA:\n                                    addedGlueRecords.Add(record);\n                                    break;\n                            }\n                        }\n                    }\n\n                    index++;\n                }\n\n                //check sequence soa serial\n                DnsSOARecordData deletedSoa = deletedSoaRecord.RDATA as DnsSOARecordData;\n\n                if (currentSoa.Serial != deletedSoa.Serial)\n                    throw new InvalidOperationException(\"Current SOA serial does not match with the IXFR difference sequence deleted SOA.\");\n\n                //sync difference sequence\n                if (deletedRecords.Count > 0)\n                {\n                    foreach (KeyValuePair<string, Dictionary<DnsResourceRecordType, List<DnsResourceRecord>>> deletedEntry in DnsResourceRecord.GroupRecords(deletedRecords))\n                    {\n                        AuthZone zone = GetOrAddSubDomainZone(zoneName, deletedEntry.Key);\n\n                        if (zone.Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase))\n                        {\n                            zone.SyncRecords(deletedEntry.Value, null);\n                        }\n                        else if ((zone is SubDomainZone subDomainZone) && subDomainZone.AuthoritativeZone.Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase))\n                        {\n                            zone.SyncRecords(deletedEntry.Value, null);\n\n                            if (zone.IsEmpty)\n                                _root.TryRemove(deletedEntry.Key, out SubDomainZone _); //remove empty sub zone","sourceCodeStart":2805,"sourceCodeEnd":2841,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/ZoneManagers/AuthZoneManager.cs#L2805-L2841","documentation":"Thrown while APPLYING an incoming Incremental Zone Transfer (IXFR) to a secondary zone. After walking each difference sequence (deleted/added records bracketed by SOA records), the server asserts that the sequence's 'deleted SOA' serial equals the local zone's current SOA serial. This guarantees the incremental delta applies against the exact base version the secondary currently holds. A mismatch means the delta is not a valid successor of the local state, so applying it would corrupt the zone.","triggerScenarios":"Secondary zone pulls IXFR from a primary whose SOA serial advanced past the delta's expected base serial; partial/truncated IXFR response where the closing deleted-SOA does not line up with local serial; serial number rollback or wrap on the primary mid-transfer; concurrent NOTIFY-triggered transfers racing a serial change.","commonSituations":"Primary's SOA serial was edited or reset manually; a long secondary chain (primary -> secondary -> secondary) accumulated serial skew; an interrupted IXFR resumed from stale state; primary switched serial numbering scheme (e.g. date-based to counter) without a full AXFR first.","solutions":["Force a full zone transfer (AXFR) for the affected secondary zone so it resynchronizes to the primary's current serial.","Verify the primary's SOA serial is monotonically increasing and obeys RFC 1982 serial arithmetic.","Delete and re-add the secondary zone (or clear its zone file) so the next transfer is a clean AXFR rather than IXFR.","Inspect primary + secondary logs for serial jumps or dropped NOTIFY messages that left the delta chain broken."],"exampleFix":"// before: secondary zone repeatedly fails IXFR with serial mismatch\n//   (server log: 'Current SOA serial does not match...')\n// after: force full reload so IXFR delta chain restarts from a known base\n//   GUI: Zones > <zone> > Manage > 'Transfer Zone Now'\n//   or remove the secondary zone and re-add it to trigger an AXFR","handlingStrategy":"retry","validationCode":"// Before accepting an IXFR, ensure local SOA serial is a valid predecessor\nvar currentSerial = secondaryZone.SOARecord.RDATA.Serial;\n// compare against the primary's current SOA before requesting IXFR\nif (!IsSerialPredecessor(currentSerial, primarySerial))\n    RequestAxfrInstead(secondaryZone); // full transfer avoids the mismatch","typeGuard":null,"tryCatchPattern":"try\n{\n    secondaryZone.DoZoneTransfer(ZoneTransferType.Ixfr);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"IXFR difference sequence\"))\n{\n    // delta chain is out of sync -> fall back to a full AXFR\n    secondaryZone.DoZoneTransfer(ZoneTransferType.Axfr);\n}","preventionTips":["Never hand-edit the primary's SOA serial; let the server advance it monotonically.","After any serial reset on the primary, force all secondaries to AXFR once.","Monitor secondary transfer logs for serial-mismatch messages and auto-trigger AXFR.","Keep the primary->secondary chain short to reduce serial skew."],"tags":["dns","ixfr","zone-transfer","soa","secondary-zone"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}