Extended DNS Errors: the server says why
SERVFAILis a shrug. An Extended DNS Error (RFC 8914) is that same shrug with a reason attached: a number, a registry name, and a line of plain text riding next to the failure. Read it and you stop guessing.
Asks a broken zone for an address and reads the reason the server attached.
dig +https @1.1.1.1 +dnssec dnssec-failed.org ASERVFAILThe server tried, and could not finish the job.
qrThis message is the answer coming back, not the question going out.
rdYou asked this server to go and find the answer for you.
raThis server says it is willing to go and find answers for you.
AYou asked for the IPv4 address this name points at.
Query timeHow long this one lookup took, start to finish.
good: SERVFAIL and an EDE line naming the reason
bad: SERVFAIL with no EDE, which leaves you guessing why
What an EDE is#
An EDE is an EDNS(0) option, option code 15, carried in the OPT record of a response. Inside it are a two-byte INFO-CODE and an optional UTF-8 EXTRA-TEXT string (RFC 8914 section 2). That is the whole format.
It does not change the rcode. SERVFAIL stays SERVFAIL and NOERROR stays NOERROR; the EDE sits beside the rcode and explains it. That matters for the codes that ride a successful answer: EDE 3 (Stale Answer) and EDE 29 (Synthesized) both arrive on a NOERROR you were happy with, and both are telling you the answer did not come from where you assumed.
One response can carry several. A resolver that cached someone else's failure often sends EDE 13 (Cached Error) wrapped around the original validation code, so read every line, not the first one.
EXTRA-TEXT is optional and free-form. When a server sends it you get a sentence; when it does not, you get a bare number and a name. Both are valid.
Watch one arrive#
dnssec-failed.org is a zone that is deliberately signed wrong. Ask for it and a validating resolver refuses, then says why. Press run.
- Who we asked. Cloudflare (
1.1.1.1), reached over DoH from a Cloudflare edge location, with DNSSEC data requested and checking left switched on. Not your machine and not your router: see the dig tool manual on where the query runs from. - What came back.
SERVFAIL, zero answer records, and one line that a bareSERVFAILwould never have given you:
;; EDE 9 DNSKEY Missing: no SEP matching the DS found for dnssec-failed.org.- What the number says.
9is the INFO-CODE.DNSKEY Missingis that code's name in the IANA registry, printed for you rather than looked up. Both come off the wire. - What the text says.
no SEP matching the DS foundis Cloudflare's EXTRA-TEXT, and it names the exact broken joint. A SEP is a Secure Entry Point, the DNSKEY flagged as the key a parent is allowed to point at (RFC 4034 section 2.1.1). The parent zoneorgpublishes a DS record that fingerprints one key. The child zone serves a different one. - Verdict. The chain is broken at the
orgtodnssec-failed.orgdelegation: the DS in the parent and the DNSKEY set in the child do not agree.EDE 9says they disagree, not which side moved, and you cannot tell from one query whether the child rolled its key or the parent published the wrong digest. Nobody had to run a second query to learn that. Fixing that class of break is the DNSSEC field guide; this page stops at reading the line.
Two resolvers, one zone, two codes#
Ask a different validator and you can get a different code for the same broken zone. Quad9, same name, same moment (captured 2026-08-25):
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
; EDE: 7 (Signature Expired)EDE 7, and no EXTRA-TEXT at all. Cloudflare stopped at the missing key; Quad9 walked further and hit a dead signature first. Neither is lying. An EDE reports the first thing that resolver tripped over, so it is evidence about one validator's path, not a verdict on the zone. dnssec-failed.org re-signs on its own schedule, so run it yourself and expect your own codes.
The code table#
Codes 0 to 24 are defined in RFC 8914 itself. Codes 25 and above were registered afterwards, several of them from drafts and vendor pull requests rather than finished RFCs, so the IANA extended DNS error codes registry is the live list. As of 2026-09-04 it assigns through 35; 36 onward is unassigned.
| Code | Name | What it is telling you |
|---|---|---|
| 0 | Other Error | The server has a reason with no code of its own. The EXTRA-TEXT is the whole message |
| 1 | Unsupported DNSKEY Algorithm | The zone signs with an algorithm this resolver does not implement |
| 2 | Unsupported DS Digest Type | The parent's DS uses a hash this resolver does not implement |
| 3 | Stale Answer | Served from cache past its TTL because the authoritative servers were unreachable (RFC 8767) |
| 4 | Forged Answer | The answer was manufactured by filtering policy rather than read from a zone |
| 5 | DNSSEC Indeterminate | The resolver could not decide whether the answer is correctly signed |
| 6 | DNSSEC Bogus | Validation ran and failed. The signatures do not check out |
| 7 | Signature Expired | The RRSIG covering the answer is past its expiration timestamp |
| 8 | Signature Not Yet Valid | The RRSIG inception is in the future. Suspect a clock, on either end |
| 9 | DNSKEY Missing | The parent published a DS and no key in the child zone matches it |
| 10 | RRSIGs Missing | The zone is supposed to be signed and the records arrived unsigned |
| 11 | No Zone Key Bit Set | A DNSKEY is present but is not flagged as a zone key, so it cannot sign |
| 12 | NSEC Missing | A "does not exist" arrived with no proof of non-existence attached |
| 13 | Cached Error | This failure is a stored copy of an earlier one, not a fresh attempt |
| 14 | Not Ready | The server is running but is not yet serving this zone |
| 15 | Blocked | The server refuses this name under its own policy |
| 16 | Censored | An external requirement forces the server to withhold the answer |
| 17 | Filtered | The client asked for this name to be blocked, via a filtering profile |
| 18 | Prohibited | The client is not permitted to query this server. An access list, not a zone fault |
| 19 | Stale NXDomain Answer | A cached "does not exist" served past its TTL because upstream was unreachable |
| 20 | Not Authoritative | An authoritative question about a zone this server does not serve |
| 21 | Not Supported | The operation asked for is not implemented here |
| 22 | No Reachable Authority | None of the zone's authoritative servers answered. Look at the auth tier, not the zone data |
| 23 | Network Error | The path to the upstream broke: reset, timeout, unreachable |
| 24 | Invalid Data | The upstream reply was malformed past the point of use |
| 25 | Signature Expired before Valid | Expiration precedes inception. The RRSIG window is inside out |
| 26 | Too Early | A 0-RTT early-data query was rejected and needs sending again after the handshake |
| 27 | Unsupported NSEC3 Iterations Value | The zone's NSEC3 iteration count is higher than the resolver will spend CPU on (RFC 9276) |
| 28 | Unable to conform to policy | The resolver could not meet the client's stated policy for the answer |
| 29 | Synthesized | The answer was generated from a rule, DNS64 style, rather than read from a zone |
| 30 | Invalid Query Type | The query type is one this server will not process |
| 31 | Rate Limited | The client is asking faster than this server will answer |
| 32 | Over Quota | The client has spent an allowance the operator set, not a per-second rate |
| 33 | Negative Trust Anchor | Validation was deliberately switched off for this name by the operator, to ride out someone else's broken zone |
| 34 | New Delegation Only | The delegation exists only in the new DELEG form, with no NS records; sent by a DELEG-aware authoritative to a resolver that does not understand DELEG (draft-ietf-deleg) |
| 35 | Blocked by Upstream DNS Server | Something further up the chain blocked it, and this server is relaying that fact rather than owning it |
Five of them cover most of what an operator meets in a bad week. 6 says validation failed and gave no detail. 9 and 10 say the signing is wrong in a specific way. 22 and 23 say the resolver never got a usable answer to validate, which is a reachability problem wearing a DNSSEC costume.
When there is no EDE to read#
The absence of an EDE is not the absence of a cause. These are the reasons a real failure comes back bare:
- The resolver does not send them. EDE is optional. Plenty of ISP and appliance resolvers still answer
SERVFAILand nothing else. - The query carried no EDNS. No OPT going out, no OPT coming back.
dig +noednsproves it in one line, below. - Your
digis too old to print it. BINDdigbegan printing theEDE:line at 9.16.4. Older builds receive the option and say nothing about it. nslookupcannot show it. It has no EDNS display at all. Neither doesdig +short, which prints nothing whatsoever on a failure.- Something on the path answered instead. An intercepting box on port 53 writes its own reply, and its reply has no reason to carry anyone else's EDE. Query over DoH or DoT when you need the resolver's own words (the encrypted transports).
- The tool path has nowhere to put it. A JSON API loses whatever its schema has no field for. Cloudflare's DoH JSON parks the string in
Comment, and a client that ignoresCommentshows you a bareStatus. - It came from an authoritative server. Most EDEs you meet are minted by a validating recursive resolver, because that is where validation happens. An authoritative server has less to report.
Losing the OPT is the one you can demonstrate on demand. Same resolver, same broken zone, EDNS switched off:
dig +https @1.1.1.1 +noedns dnssec-failed.org A;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 20304
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0ADDITIONAL: 0. No OPT record, so no option 15, so no reason. The failure is identical and the explanation is gone.
Reading one from the command line#
dig prints the EDE whenever the response carries the option. There is no flag that turns the display on: +ede and +noede are rejected as invalid options on DiG 9.20.24, and the only relevant switch is +noedns, which removes the OPT from the query and takes the answer's EDE with it.
dig +https @1.1.1.1 +dnssec dnssec-failed.org A;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 42642
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
; EDE: 9 (DNSKEY Missing): (no SEP matching the DS found for dnssec-failed.org.)+https sends the query over DoH (RFC 8484) so that nothing on your local port-53 path can answer in Cloudflare's place. It needs BIND dig 9.18 or newer. Drop it once you trust your own path, and keep it whenever the answer is the evidence.
kdig from the Knot utilities prints the same option, quoting the EXTRA-TEXT instead of bracketing it:
kdig +https @1.1.1.1 +dnssec dnssec-failed.org A;; EDNS PSEUDOSECTION:
;; Version: 0; flags: do; UDP size: 1232 B; ext-rcode: NOERROR
;; EDE: 9 (DNSKEY Missing): 'no SEP matching the DS found for dnssec-failed.org.'When the local dig is too old to print the line, ask over DoH JSON and read Comment:
curl -s -H 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=dnssec-failed.org&type=A'{"Status":2,"AD":false,
"Comment":["EDE(9): DNSKEY Missing no SEP matching the DS found for dnssec-failed.org."]}Status 2 is SERVFAIL. The Comment array is where Cloudflare puts the EDE string, code and name and text run together into one line. Quoting that string into a ticket beats describing the failure in your own words, every time.
See also#
- What does SERVFAIL mean?: the rcode these codes are explaining, and the five causes told apart one dig at a time
- DNSSEC troubleshooting: what to do once the EDE has named the break, with the triage flow and the operational checklist
- DNSSEC, signed and validated: how the trust chain is built, so
EDE 9andEDE 10mean something concrete - The DNSSEC chain, drawn and tldr-dnssec: the same broken zone as a picture and as one verdict line
- The isitdns dig tool: the manual for the widget on this page, including what the tool can and cannot see
- dig flags:
+dnssec,+cd,+noednsand every other switch used here - Glossary and RFC index: the one-line definition, and RFC 8914 in the shelf