{"record":{"id":"95633d8d52ead6b8","repo":"TechnitiumSoftware/DnsServer","slug":"invalid-soa-record-95633d","errorCode":null,"errorMessage":"Invalid SOA record.","messagePattern":"Invalid SOA record\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Zones/PrimaryZone.cs","lineNumber":2537,"sourceCode":"                        foreach (DnsResourceRecord record in records)\n                        {\n                            if (record.GetAuthGenericRecordInfo().Disabled)\n                                throw new DnsServerException(\"Cannot set records: disabling records in a signed zones is not supported.\");\n                        }\n\n                        break;\n                }\n            }\n\n            switch (type)\n            {\n                case DnsResourceRecordType.CNAME:\n                case DnsResourceRecordType.DS:\n                    throw new InvalidOperationException(\"Cannot set \" + type.ToString() + \" record at zone apex.\");\n\n                case DnsResourceRecordType.SOA:\n                    if ((records.Count != 1) || !records[0].Name.Equals(_name, StringComparison.OrdinalIgnoreCase))\n                        throw new InvalidOperationException(\"Invalid SOA record.\");\n\n                    DnsResourceRecord newSoaRecord = records[0];\n                    DnsSOARecordData newSoa = newSoaRecord.RDATA as DnsSOARecordData;\n\n                    if (newSoaRecord.OriginalTtlValue > newSoa.Expire)\n                        throw new DnsServerException(\"Cannot set record: TTL cannot be greater than SOA EXPIRE.\");\n\n                    if (newSoa.Retry > newSoa.Refresh)\n                        throw new DnsServerException(\"Cannot set record: SOA RETRY cannot be greater than SOA REFRESH.\");\n\n                    if (newSoa.Refresh > newSoa.Expire)\n                        throw new DnsServerException(\"Cannot set record: SOA REFRESH cannot be greater than SOA EXPIRE.\");\n\n                    //remove any record info except serial date scheme and comments\n                    bool useSoaSerialDateScheme;\n                    string comments;\n                    {\n                        SOARecordInfo recordInfo = newSoaRecord.GetAuthSOARecordInfo();","sourceCodeStart":2519,"sourceCodeEnd":2555,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimaryZone.cs#L2519-L2555","documentation":"Thrown as InvalidOperationException by PrimaryZone.SetRecords() in the SOA case when the input does not contain exactly one record, or that record's name does not equal the zone's apex name (_name). A zone must have exactly one SOA at its apex; any other shape is malformed input.","triggerScenarios":"Calling SetRecords(DnsResourceRecordType.SOA, records) where records.Count != 1, or where records[0].Name does not case-insensitively equal the zone apex name.","commonSituations":"Passing an empty or multi-element SOA list; passing an SOA record whose owner name was rewritten (e.g. to a subdomain) during import; constructing SOA records programmatically without setting the owner name to the zone name.","solutions":["Ensure exactly one SOA record is passed and that its Name equals the zone apex name (case-insensitive).","Normalize imported SOA records by overwriting their Name with the zone apex before calling SetRecords.","Validate records.Count == 1 and the name match before the call."],"exampleFix":"// before\nzone.SetRecords(DnsResourceRecordType.SOA, soaRecords); // throws if count!=1 or name mismatch\n\n// after\nvar soa = soaRecords.Single();\nsoa = new DnsResourceRecord(zoneName, soa.Type, soa.Class, soa.OriginalTtlValue, soa.RDATA);\nzone.SetRecords(DnsResourceRecordType.SOA, new[] { soa });","handlingStrategy":"validation","validationCode":"// Validate SOA shape before SetRecords.\nif (type == DnsResourceRecordType.SOA)\n{\n    if (records.Count != 1)\n        throw new ArgumentException(\"SOA must have exactly one record.\");\n    if (!records[0].Name.Equals(zone.Name, StringComparison.OrdinalIgnoreCase))\n        throw new ArgumentException(\"SOA owner name must equal the zone apex.\");\n}\n\nzone.SetRecords(type, records);","typeGuard":"static bool IsValidApexSoa(IReadOnlyList<DnsResourceRecord> rs, string zoneName) =>\n    rs.Count == 1 && rs[0].Name.Equals(zoneName, StringComparison.OrdinalIgnoreCase);","tryCatchPattern":"try { zone.SetRecords(type, records); }\ncatch (InvalidOperationException ex) when (ex.Message == \"Invalid SOA record.\")\n{ Log.Error(\"SOA must be a single record whose name equals the zone apex.\"); }","preventionTips":["Always set the SOA owner name to the zone apex when constructing it.","Reject SOA lists with Count != 1 upstream.","Normalize imported SOA owner names to the target zone name."],"tags":["dns","record","soa","apex","invalidoperation","validation"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}