SPF void lookups: the 2-lookup limit that fails quietly
Breakage - dead includes and void lookups trigger permerror independent of the 10-lookup cap
Critical
Your SPF record produces more void lookups than the specification allows, or contains a deadinclude target. This fires independently of the 10-lookup limit and can trip even when your total lookup count looks fine.
What counts as a void lookup
RFC 7208 section 4.6.4 defines void lookups as DNS queries during SPF evaluation that return either RCODE 0 (NOERROR) with an answer count of zero, or RCODE 3 (Name Error, better known as NXDOMAIN). In plain terms: the query came back with nothing usable.
The spec says implementations SHOULD limit these to two, and that exceeding the limit producespermerror. Note the SHOULD rather than MUST. The 10-lookup cap is a hard requirement; the void limit is a strong recommendation. In practice the major receivers enforce it, but the softer normative language is part of why behaviour here is less uniform than people expect.
Why it fires when your record looks fine
The two limits are counted separately. A record with four include mechanisms is nowhere near the lookup cap. If three of those four point at names that no longer resolve, you are over the void limit and the evaluation ends in permerror anyway.
That makes this a drift problem rather than a design problem. Records rarely start with void lookups. They acquire them, quietly, as the things they point at go away.
Where void lookups come from
- A provider retired or renamed their SPF domain. You stop paying attention after the initial setup. They consolidate infrastructure and drop the old name. Your include now points at nothing.
- A service was decommissioned on your side but never removed from the record. Offboarding a vendor usually covers the account, the billing, and the API keys. The DNS entry that authorized them to send as you is easy to forget.
- An
aormxtarget that no longer exists. A host was retired, a subdomain was cleaned up, or a zone was rebuilt without an old record. - A typo that never worked. A single typo can sit there for years - nothing visibly fails at low counts, so it stays undetected.
A nuance worth knowing: dead includes vs. void lookups
Not every dead mechanism reaches you through the void counter, and understanding the difference helps when you are reading a failure.
For a, mx, and exists, the spec says that when a lookup returns Name Error the mechanism continues as if it had returned zero answers. The mechanism simply does not match, evaluation carries on, and the void counter goes up by one. These are the classic void lookups.
For include, the path is different. An include triggers a recursive evaluation. If the recursive check returns none - which is what happens when there is no SPF record at the target - the spec says the include mechanism returns permerror directly. Not a void lookup - an immediate hard error.
So on a strict implementation, one dead include is enough to permerror on its own, ahead of any counting. Real-world implementations vary in strictness, but the practical upshot is the same: a dead include is a defect that needs removing.
How to fix it
- Resolve every
include,a,mx, andexiststarget in the record as it stands today, and note which come back NXDOMAIN or with an empty answer. The DNSAudit finding lists the ones it hit, so start there. - For each dead target, decide whether you still use that sender. If you do not, delete the mechanism. This is the clean case and it is most of them.
- If you still use the sender, get their current include value from their documentation. Providers that renamed an SPF domain usually publish the replacement. If they no longer offer an include, list their sending IPs with
ip4/ip6instead. - Fix typos against the provider's documented value, character by character. Do not correct a hostname from memory.
- Re-scan. Because this check needs live resolution, the result reflects DNS exactly as it looks right now.
The structural fix is process, not DNS. Add "remove the SPF entry" to whatever checklist you use when you stop using a sending service. It costs nothing at the time and prevents the slow accumulation that produces this finding two years later.
How this is rated
Like the lookup limit, this is a breakage finding that ends in permerror, so DNSAudit rates more than two void lookups Critical. It is the softest Critical in the SPF set: the void limit is a SHOULD rather than a MUST, so receivers enforce it less uniformly, and crossing it takes three or more genuinely dead lookups.
One case is rated higher than the count alone would suggest: a single dead include that points at a name with no SPF record can produce permerror on its own on a strict receiver, ahead of any counting. So a lone dead include is flagged even when the void count has not crossed the line.
Related checks
Reference: RFC 7208 section 4.6.4 (void lookup limit), section 5 (Name Error handling in mechanisms), section 5.2 (the include result table).
