{"record":{"id":"b76c7c9b9672fd38","repo":"TechnitiumSoftware/DnsServer","slug":"cannot-set-type-record-at-zone-apex","errorCode":null,"errorMessage":"Cannot set {type} record at zone apex.","messagePattern":"Cannot set (.+?) record at zone apex\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"DnsServerCore/Dns/Zones/PrimaryZone.cs","lineNumber":2533,"sourceCode":"                    case DnsResourceRecordType.APP:\n                        throw new DnsServerException(\"The record type is not supported by DNSSEC signed primary zones.\");\n\n                    default:\n                        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","sourceCodeStart":2515,"sourceCodeEnd":2551,"githubUrl":"https://github.com/TechnitiumSoftware/DnsServer/blob/d0484b6c1e7439cdc53d67d81e9c876cda2ad756/DnsServerCore/Dns/Zones/PrimaryZone.cs#L2515-L2551","documentation":"Thrown as InvalidOperationException by PrimaryZone.SetRecords() when the requested type is CNAME or DS. A CNAME at the zone apex is illegal (RFC 1034: apex must have SOA/NS) and a DS record is managed by the parent zone, not set locally at the apex. This is a programming/usage error, not an operational condition.","triggerScenarios":"Calling SetRecords(DnsResourceRecordType.CNAME, ...) or SetRecords(DnsResourceRecordType.DS, ...) on a primary zone (these types resolve to the apex-rejection branch in the switch).","commonSituations":"Generic record-management code that iterates all record types and calls SetRecords for each without excluding CNAME/DS; importing a foreign zone file that places a CNAME at the apex.","solutions":["Never call SetRecords with CNAME or DS on a primary zone; CNAME is illegal at the apex and DS belongs in the parent zone.","Guard the call site with a type check that skips CNAME/DS.","Use the zone's specific APIs (parent-zone DS management, non-apex CNAME handling) instead of SetRecords for these types."],"exampleFix":"// before\nzone.SetRecords(type, records); // throws for CNAME/DS\n\n// after\nif (type != DnsResourceRecordType.CNAME && type != DnsResourceRecordType.DS)\n    zone.SetRecords(type, records);","handlingStrategy":"type-guard","validationCode":"if (type == DnsResourceRecordType.CNAME || type == DnsResourceRecordType.DS)\n    throw new ArgumentException($\"{type} cannot be set at the zone apex.\");\n\nzone.SetRecords(type, records);","typeGuard":"static bool IsApexSettable(DnsResourceRecordType t) =>\n    t != DnsResourceRecordType.CNAME && t != DnsResourceRecordType.DS;","tryCatchPattern":"try { zone.SetRecords(type, records); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"record at zone apex\"))\n{ Log.Error($\"{type} is illegal at the apex: {ex.Message}\"); }","preventionTips":["Never route CNAME/DS through SetRecords on a primary zone.","Model apex record types explicitly in importers.","Treat InvalidOperationException from SetRecords as a caller bug, not a runtime condition."],"tags":["dns","record","cname","ds","apex","invalidoperation","validation"],"backgroundTag":null,"analyzedSha":"d0484b6c1e7439cdc53d67d81e9c876cda2ad756","analyzedAt":"2026-08-13T22:57:35.508Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}