rfc2136 provider can write MX records but cannot read them back (AXFR handler has no MX case)

Author: saikatdas0790Created Sep 24, 2026Updated Sep 24, 2026

What happened

The rfc2136 provider writes MX records correctly, but cannot list them back. Records() (which uses AXFR via List()) switches over the record type and has no MX case, so any MX in the zone is dropped before it reaches the plan:

go
// provider/rfc2136/rfc2136.go — Records()
switch rr.Header().Rrtype {
case dns.TypeCNAME: ...
case dns.TypeDNAME: ...
case dns.TypeA:     ...
case dns.TypeAAAA:  ...
case dns.TypeTXT:   ...
case dns.TypeNS:    ...
case dns.TypePTR:   ...
default:
    continue // Unhandled record type
}

The write path is type-agnostic (AddRecord just formats <name> <ttl> <type> <target> and calls dns.NewRR), so --managed-record-types=MX with a CRD source does create the record and its ownership marker. It then becomes invisible to the next reconcile.

What you expected to happen

A record external-dns creates should be readable by external-dns, so it can be updated or deleted like any other managed record.

How to reproduce it

--provider=rfc2136 --source=crd --registry=txt --policy=sync --rfc2136-axfr --managed-record-types=A --managed-record-types=MX, with an MX in a DNSEndpoint at a non-apex name (apex names hit a separate issue, kubernetes-sigs/external-dns#6125, and are silently blocked before this point).

Create is logged and works:

Adding RR: mxprobe.oleole.ai 300 MX 1 smtp.google.com
Adding RR: mx-mxprobe.oleole.ai 0 TXT "heritage=external-dns,external-dns/owner=...,resource=crd/.../oleole-ai-workspace-verification"

The record and its marker exist in the zone and resolve. Then remove the endpoint and reconcile: no Removing RR: is ever logged, and the MX plus its ownership TXT remain in the zone indefinitely. Same for a target change — the old value is not replaced.

Verified the write itself is fine by reading the zone directly:

sql
mxprobe.oleole.ai        | MX  | smtp.google.com
mx-mxprobe.oleole.ai     | TXT | "heritage=external-dns,external-dns/owner=...,resource=..."

So the record is present, owned, and in the AXFR output — it is simply discarded by the default: continue arm.

Anything else we need to know?

Two related observations:

  • SupportedRecordType is a separate gate and not the cause here. provider/recordfilter.go excludes MX, and neither rfc2136 nor pdns overrides it, unlike aws/azure/cloudflare/google. But the plan's own filter (IsManagedRecord) honours --managed-record-types, which is why the create works. Fixing the AXFR case is what makes the record manageable; whether SupportedRecordType also needs MX is a separate question (see #6180).

  • DNAME is in the Records() switch but not in SupportedRecordType, which suggests the two lists have drifted. May be worth reconciling both in one pass.

Environment

  • External-DNS version: v0.23.0 (also present on current master)
  • DNS provider: rfc2136 → PowerDNS Authoritative 5.2 (gpgsql backend), TSIG, --rfc2136-axfr enabled
  • Registry: txt (--txt-owner-id set)
  • Source: crd (DNSEndpoint)

Source: kubernetes-sigs/external-dns