TechnitiumSoftware/DnsServer · error · InvalidOperationException

Cannot add record: use SetRecords() for {type} record.

Error message

Cannot add record: use SetRecords() for {type} record.

What it means

AuthZone.AddRecord explicitly rejects CNAME, DNAME, and SOA record types with InvalidOperationException. These types are singleton-per-name records with special semantics: SOA is the zone's Start of Authority (one per zone), and CNAME/DNAME are exclusive types that cannot coexist with others. The library requires you to use SetRecords() instead, which performs the proper validation and atomic replacement logic for these singleton types.

Source

Thrown at DnsServerCore/Dns/Zones/AuthZone.cs:312

                }

                updatedRecords.AddRange(newRRSigRecords);

                deleted = deletedRecords;
                return updatedRecords;
            });

            deletedRRSigRecords = deleted;
        }

        internal void AddRecord(DnsResourceRecord record, out IReadOnlyList<DnsResourceRecord> addedRecords, out IReadOnlyList<DnsResourceRecord> deletedRecords)
        {
            switch (record.Type)
            {
                case DnsResourceRecordType.CNAME:
                case DnsResourceRecordType.DNAME:
                case DnsResourceRecordType.SOA:
                    throw new InvalidOperationException("Cannot add record: use SetRecords() for " + record.Type.ToString() + " record.");

                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;
            }

            List<DnsResourceRecord> added = new List<DnsResourceRecord>();
            List<DnsResourceRecord> deleted = new List<DnsResourceRecord>();

            addedRecords = added;
            deletedRecords = deleted;

            _entries.AddOrUpdate(record.Type, delegate (DnsResourceRecordType key)
            {
                added.Add(record);
                return [record];

View on GitHub (pinned to d0484b6c1e)

Solutions

  1. Use SetRecords(type, [record]) for CNAME, DNAME, and SOA records instead of AddRecord(record).
  2. Add a type check in calling code: if the record type is CNAME/DNAME/SOA, route to SetRecords; otherwise use AddRecord.
  3. For SOA modifications specifically, use the zone's dedicated SOA management methods (e.g., increment serial via the zone's built-in mechanism).

Example fix

// before
zone.AddRecord(new DnsResourceRecord(name, DnsResourceRecordType.SOA, ...));
// throws: use SetRecords() for SOA record

// after
zone.SetRecords(DnsResourceRecordType.SOA, new[] { soaRecord });
Defensive patterns

Strategy: type-guard

Validate before calling

static bool RequiresSetRecords(DnsResourceRecordType type)
    => type == DnsResourceRecordType.CNAME
    || type == DnsResourceRecordType.DNAME
    || type == DnsResourceRecordType.SOA;

if (RequiresSetRecords(record.Type))
    zone.SetRecords(record.Type, new[] { record });
else
    zone.AddRecord(record);

Type guard

static bool CanAddRecord(DnsResourceRecordType type)
    => type != DnsResourceRecordType.CNAME
    && type != DnsResourceRecordType.DNAME
    && type != DnsResourceRecordType.SOA;

Prevention

When it happens

Trigger: Calling the internal AddRecord method (or the public AddRecord wrapper) with a DnsResourceRecord whose Type is CNAME, DNAME, or SOA. This happens when application code uses AddRecord for a record type that must be managed exclusively via SetRecords.

Common situations: Programmatic zone management code that treats all record types uniformly through AddRecord; migration scripts that add records in a loop without type-specific routing; web API handlers that incorrectly route SOA/CNAME/DNAME modifications through AddRecord.

Related errors


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