TechnitiumSoftware/DnsServer · error · InvalidOperationException
Cannot add record: a CNAME record cannot exists with other r
Error message
Cannot add record: a CNAME record cannot exists with other record types for the same name.
What it means
Inside AuthZone.TrySetRecords (internal), the CNAME case enforces RFC 1034 section 3.6.2: a CNAME resource record cannot coexist with any other record type at the same DNS name. If the zone's _entries dictionary is non-empty and does NOT already contain a CNAME entry (meaning other record types are present), setting a CNAME throws InvalidOperationException. This is a fundamental DNS protocol constraint, not an arbitrary library restriction.
Source
Thrown at DnsServerCore/Dns/Zones/AuthZone.cs:135
rrsigRecord.GetAuthGenericRecordInfo().LastUsedOn = utcNow;
newRecords.Add(rrsigRecord);
}
}
return newRecords;
}
#endregion
#region versioning
internal bool TrySetRecords(DnsResourceRecordType type, IReadOnlyList<DnsResourceRecord> records, out IReadOnlyList<DnsResourceRecord> deletedRecords)
{
switch (type)
{
case DnsResourceRecordType.CNAME:
if ((!_entries.IsEmpty) && !_entries.ContainsKey(DnsResourceRecordType.CNAME))
throw new InvalidOperationException("Cannot add record: a CNAME record cannot exists with other record types for the same name.");
break;
case DnsResourceRecordType.NSEC:
case DnsResourceRecordType.RRSIG:
break; //ignore
default:
if (_entries.ContainsKey(DnsResourceRecordType.CNAME))
throw new InvalidOperationException("Cannot add record: a CNAME record cannot exists with other record types for the same name.");
break;
}
if (_entries.TryGetValue(type, out IReadOnlyList<DnsResourceRecord> existingRecords))
{
deletedRecords = existingRecords;
return _entries.TryUpdate(type, records, existingRecords);View on GitHub (pinned to d0484b6c1e)
Solutions
- Delete all existing records for the name before setting a CNAME (call DeleteRecords for each existing type first).
- Use SetRecords with type=CNAME which routes through the same guard — clear _entries of conflicting types first.
- Switch to an A/AAAA record pointing to the target IP instead of using a CNAME if coexistence is required.
- Validate that _entries is empty or contains only CNAME before attempting the CNAME assignment.
Example fix
// before
zone.TrySetRecords(DnsResourceRecordType.CNAME, cnameRecords, out _);
// throws if A records exist
// after
foreach (var type in zone.GetRecordTypes())
zone.DeleteRecords(type);
zone.TrySetRecords(DnsResourceRecordType.CNAME, cnameRecords, out _); Defensive patterns
Strategy: validation
Validate before calling
// Before setting CNAME, ensure no other record types exist
bool hasOtherTypes = zone.GetRecordTypes().Any(t => t != DnsResourceRecordType.CNAME
&& t != DnsResourceRecordType.NSEC && t != DnsResourceRecordType.RRSIG);
if (hasOtherTypes)
throw new InvalidOperationException("Cannot set CNAME: other record types exist. Delete them first.");
zone.SetRecords(DnsResourceRecordType.CNAME, cnameRecords); Try / catch
try { zone.SetRecords(DnsResourceRecordType.CNAME, cnameRecords); }
catch (InvalidOperationException ex) when (ex.Message.Contains("CNAME"))
{ /* clear conflicting records and retry, or report to user */ } Prevention
- Always check for existing non-CNAME records before setting a CNAME.
- Treat CNAME as a mutually exclusive record type in provisioning logic.
- When importing zone data, validate RFC 1034 CNAME exclusivity before applying.
When it happens
Trigger: Calling the internal TrySetRecords method with type=DnsResourceRecordType.CNAME when the zone node (_entries) already contains records of other types (A, AAAA, MX, TXT, etc.). Typically reached indirectly through SetRecords or zone-transfer logic that routes through TrySetRecords.
Common situations: Migrating an A record to a CNAME alias without first deleting the existing A record; importing zone data from a misconfigured source; automated provisioning scripts that set CNAME without checking existing records; copying records between zones where the target already has records.
Related errors
- Cannot add record: {type} record already exists for the same
- Cannot add record: use SetRecords() for {type} record.
- Cannot update record: use SetRecords() for {type} record
- Old and new record types do not match.
- Cannot update record: the old record does not exists.
AI-assisted analysis of TechnitiumSoftware/DnsServer@d0484b6c1e (2026-08-13).
Data as JSON: /api/errors/f50d688835ab1e09.
Report an issue: GitHub.