TechnitiumSoftware/DnsServer · error · InvalidOperationException

Cannot set SOA record on sub domain.

Error message

Cannot set SOA record on sub domain.

What it means

ForwarderSubDomainZone.SetRecords rejects SOA records with InvalidOperationException. A ForwarderSubDomainZone represents a sub-domain delegation within a forwarder zone — it is not a zone apex and therefore cannot have its own SOA record. The SOA belongs to the parent forwarder zone. Allowing a sub-domain to have its own SOA would violate DNS zone hierarchy rules (RFC 1034 section 4.2.1).

Solutions

  1. Set the SOA record on the parent ForwarderZone (the apex), not on the ForwarderSubDomainZone.
  2. Add a zone-type check: skip SOA operations on sub-domain zones.
  3. Filter SOA records out when applying records to sub-domain nodes.

Example fix

// before
subDomainZone.SetRecords(DnsResourceRecordType.SOA, soaRecords);
// throws: Cannot set SOA record on sub domain

// after
// set SOA on the parent forwarder zone apex instead:
forwarderZone.SetRecords(DnsResourceRecordType.SOA, soaRecords);
// skip SOA for sub-domain nodes
Defensive patterns

Strategy: type-guard

Validate before calling

if (zone is ForwarderSubDomainZone && type == DnsResourceRecordType.SOA)
    throw new InvalidOperationException("Cannot set SOA on a forwarder sub-domain. Set SOA on the parent forwarder zone apex.");
zone.SetRecords(type, records);

Type guard

static bool CanSetSoa(Zone zone) => zone is not ForwarderSubDomainZone;

Prevention

When it happens

Trigger: Calling SetRecords(DnsResourceRecordType.SOA, records) on a ForwarderSubDomainZone instance. Occurs when zone-management code attempts to set SOA on a sub-domain node of a forwarder zone rather than on the zone apex.

Common situations: Generic zone-management code that applies SOA settings to all zone nodes including sub-domains; importing zone data where SOA records are pushed to all nodes; scripts that iterate zone nodes and set SOA uniformly; misidentifying a sub-domain node as the zone apex.

Related errors


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

Appendix: source

Thrown at DnsServerCore/Dns/Zones/ForwarderSubDomainZone.cs:51

        #region constructor

        public ForwarderSubDomainZone(ForwarderZone forwarderZone, string name)
            : base(forwarderZone, name)
        {
            _forwarderZone = forwarderZone;
        }

        #endregion

        #region public

        public override void SetRecords(DnsResourceRecordType type, IReadOnlyList<DnsResourceRecord> records)
        {
            switch (type)
            {
                case DnsResourceRecordType.SOA:
                    throw new InvalidOperationException("Cannot set SOA record on sub domain.");

                case DnsResourceRecordType.DS:
                case DnsResourceRecordType.DNSKEY:
                case DnsResourceRecordType.RRSIG:
                case DnsResourceRecordType.NSEC:
                case DnsResourceRecordType.NSEC3PARAM:
                case DnsResourceRecordType.NSEC3:
                    throw new InvalidOperationException("Cannot set DNSSEC records.");

                default:
                    if (records[0].OriginalTtlValue > _forwarderZone.GetZoneSoaExpire())
                        throw new DnsServerException("Cannot set records: TTL cannot be greater than SOA EXPIRE.");

                    if (!TrySetRecords(type, records, out IReadOnlyList<DnsResourceRecord> deletedRecords))
                        throw new DnsServerException("Cannot set records. Please try again.");

                    _forwarderZone.CommitAndIncrementSerial(deletedRecords, records);

View on GitHub (pinned to d0484b6c1e)