/errors/dns/dns-resolver-nxdomain-query-name-does-not-exist
dns.resolver.NXDOMAIN: The DNS query name does not exist
- tool
- DNS
- exit code
- 1
- versions
- dnspython 2.x
- os
- any
dns.resolver.NXDOMAIN: The DNS query name does not exist: typo.example.test. is raised by Python's dnspython when the DNS server answers with rcode NXDOMAIN: the name does not exist at all, for any record type. That is a definite answer, not a network problem. Check the spelling and the zone. If the name exists but has no record of the type you asked for, dnspython raises dns.resolver.NoAnswer instead.
Reproduce it
A tiny DNS server on 127.0.0.1, written with dnspython, that knows only app.example.test (A record), and a resolver pointed at it:
cat > nx.py <<'EOF'
import socket, threading
import dns.message, dns.rcode, dns.rdatatype, dns.resolver, dns.rrset
def serve(sock):
while True:
data, addr = sock.recvfrom(4096)
q = dns.message.from_wire(data)
r = dns.message.make_response(q)
name = q.question[0].name.to_text()
if name == "app.example.test.":
if q.question[0].rdtype == dns.rdatatype.A:
r.answer.append(dns.rrset.from_text(name, 300, "IN", "A", "192.0.2.10"))
else:
r.set_rcode(dns.rcode.NXDOMAIN)
sock.sendto(r.to_wire(), addr)
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind(("127.0.0.1", 4925))
threading.Thread(target=serve, args=(s,), daemon=True).start()
res = dns.resolver.Resolver(configure=False)
res.nameservers = ["127.0.0.1"]
res.port = 4925
for name, rtype in [("app.example.test", "A"), ("typo.example.test", "A"), ("app.example.test", "AAAA")]:
try:
print(name, rtype, "->", [r.to_text() for r in res.resolve(name, rtype)])
except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e:
print(name, rtype, "->", f"{type(e).__module__}.{type(e).__name__}: {e}")
EOF
uv run -q --no-project --python 3.13 --with dnspython==2.8.0 python nx.pyOutput
app.example.test A -> ['192.0.2.10'] typo.example.test A -> dns.resolver.NXDOMAIN: The DNS query name does not exist: typo.example.test. app.example.test AAAA -> dns.resolver.NoAnswer: The DNS response does not contain an answer to the question: app.example.test. IN AAAA
NXDOMAIN vs NoAnswer vs timeouts
| Exception | DNS answer | Meaning |
|---|---|---|
| dns.resolver.NXDOMAIN | rcode NXDOMAIN | The name does not exist for any type |
| dns.resolver.NoAnswer | rcode NOERROR, empty answer | The name exists, but has no record of this type (often AAAA or MX) |
| dns.resolver.NoNameservers | SERVFAIL or REFUSED from every server | The servers could not or would not answer |
| dns.resolver.LifetimeTimeout | No answer in time | Network or resolver problem; retry or check connectivity |
import dns.resolver
try:
answers = dns.resolver.resolve("example.org", "MX")
except dns.resolver.NXDOMAIN:
... # the domain does not exist: report it, do not retry
except dns.resolver.NoAnswer:
... # no MX: fall back to the A record, as mail servers doPass raise_on_no_answer=False to resolve() to get an empty answer instead of NoAnswer. NXDOMAIN is always raised, because there is no answer section to return.
Check the zone
NXDOMAIN from a recursive resolver can be a cached negative answer (kept for the SOA minimum TTL). Ask the authoritative server directly to see the current state: dig typo.example.com @ns1.example.com. If it answers, flush or wait out the negative cache of your resolver.