Use lowercase resolve() or match your dnspython version; the Resolve name doesn’t exist on the Resolver class.
Hit this traceback and your DNS code stops cold. The cause is predictable. In Python, names are case sensitive, and the dnspython resolver exposes a lowercase resolve() method. Older dnspython 1.x used query(). Mixing those APIs or capitalizing the call triggers the crash string you see on screen. The steps below get you back to clean lookups without a rewrite.
Quick Fixes For Most Projects
- Call the right method name — Change
res.Resolve()tores.resolve(). Python treatsResolveandresolveas different names. - Align the library version and API — Use
resolver.resolve()with dnspython 2.x; useresolver.query()with 1.x. Pick one path and keep it consistent across the repo. - Pin a compatible release — If your code expects
resolve(), installdnspython >= 2.0. If a vendor tool still callsquery(), keep 1.16.0 until you can update it. Issue threads for DNSRecon show exactly this mismatch.
Goal: one API surface per project. A pin in your lock file stops surprise upgrades, and a tiny wrapper lets you migrate at your pace.
AttributeError: ‘Resolver’ Object Has No Attribute ‘Resolve’ — Why It Happens
Quick check: confirm which method your code calls, then confirm the dnspython version that actually loads at runtime. Two common paths lead to the same crash:
- Wrong capitalization — The class exposes
resolve(). A capitalRproduces an attribute lookup miss, so the interpreter raises the exact string: AttributeError: ‘Resolver’ object has no attribute ‘Resolve’. - API drift across major versions — dnspython 1.x names the method
query(); dnspython 2.x renamed it toresolve(). Code written for 2.x that runs on 1.x will fail on the missing method. Tools in the wild report this when a system package and a venv disagree on versions.
Many security and ops images ship a distro package for dnspython while your application also installs a wheel through pip. The import path that wins decides the API you get. Prints of the module path and version make this visible in one line.
Fix By Version And API
Pick your target: modern code should use dnspython 2.x with resolve(). Legacy stacks tied to 1.16.0 can stay put and call query() until you schedule an upgrade.
| dnspython Series | Resolver Method | Notes |
|---|---|---|
| 1.x (e.g., 1.16.0) | query() |
Old API; many pentest tools still pin here. Threads tie breakages to mixing this with resolve(). |
| 2.x (current) | resolve() |
Active docs and examples use this method across Resolver and helpers. |
Commands that keep the API steady:
- Stay on 2.x —
pip install "dnspython>=2.3,<3" - Stay on 1.16.0 —
pip install "dnspython==1.16.0" - Clean mixed installs —
pip uninstall -y dnspython, then reinstall inside your venv with the chosen pin. On apt-based images, avoid importing the distro package from app code.
Resolver Has No Attribute Resolve Error — Close Variations And Search-Friendly Phrasing
Search logs show variations like “resolver has no attribute resolve,” “dns resolver resolve missing,” or “resolver object no resolve method.” These point to the same root cause: a capitalized call or a version drift. Using a clear, natural phrase in your internal docs helps teammates land on one fix path fast. Keep the exact crash text available for log searches, then present the corrected method and the version guidance right next to it.
Diagnose And Patch With Confidence
Identify What’s Loaded
- Print the version —
import dns, dns.resolver; print(dns.__version__). If you see1.16.0but your code callsresolve(), that mismatch explains the crash. The 2.x docs confirm the method name. - Print the module path —
import dns, inspect; print(inspect.getfile(dns)). A path inside a system site-packages while you thought you were in a venv means a shadowed install. - Scan the repo for capitalization — A quick grep for
.Resolve(or.Resolve (catches typos that slipped through code review.
Drop In A Compatibility Wrapper
Quick check: use a tiny function so call sites don’t care which major version runs today. When you finish the upgrade, remove the fallback.
from dns import resolver
_resolver = resolver.Resolver()
def dns_lookup(name, rdtype='A', **kwargs):
# Prefer 2.x; fall back to 1.x if needed.
try:
return _resolver.resolve(name, rdtype, **kwargs)
except AttributeError:
return _resolver.query(name, rdtype, **kwargs)
Pin The Version That Matches Your Calls
- Pin for
resolve()—pip install "dnspython>=2.3,<3" - Pin for
query()—pip install "dnspython==1.16.0" - Record the pin — Add it to
requirements.txtor your lock file so CI runs the same stack. DNSRecon discussions show how drift bites mixed setups.
Fix The Call Site
- Lowercase the method — Replace every
.Resolve(with.resolve(in your codebase. - Switch
querytoresolveduring upgrade — Move call signatures over and run a short smoke test with A and PTR lookups. - Set nameservers explicitly — When debugging, point at stable resolvers so tests don’t flap. The library accepts a
nameserverslist on theResolverinstance.
Verify, Edge Cases, And Stable Snippets
Verification Steps
- Run a known-good A query —
example.comshould return at least one address or a clear NXDOMAIN. - Test reverse lookups — Call the PTR helper or pass
'PTR'to confirm reverse resolution works end to end. The docs show the supported helpers in 2.x. - Exercise timeouts — Pass
lifetimeandtimeoutkwargs and watch retry behavior in logs.
Common Edge Cases
- Mixed installs — Remove stray copies with
pip uninstall dnspython, then reinstall inside the venv. On apt images, ensure app code imports the venv package, not the distro one. DNSRecon users ran into exactly this mix. - Shadowed modules — A local file named
dns.pyor a folder nameddnscan mask the library. Rename it and re-test. - Third-party scripts — Some tools still target 1.x. If you can’t patch them, run them in a pinned virtual environment to avoid stepping on your app’s 2.x.
Minimal, Tested Resolver Snippet For 2.x
import dns.resolver
def a_records(host):
r = dns.resolver.Resolver()
r.nameservers = ['8.8.8.8', '1.1.1.1']
return [rr.address for rr in r.resolve(host, 'A')]
print(a_records('example.com'))
# Expect a list of IPv4 strings or an exception on empty answers.
Minimal, Tested Resolver Snippet For 1.x
import dns.resolver
def a_records_legacy(host):
r = dns.resolver.Resolver()
r.nameservers = ['8.8.8.8', '1.1.1.1']
return [rr.address for rr in r.query(host, 'A')]
print(a_records_legacy('example.com'))
Keep The Exact Crash Text For Tracking
You may still need the string for bug tickets or log searches: AttributeError: ‘Resolver’ object has no attribute ‘Resolve’. Use it in the issue title so teammates can map alerts to this fix. In the code, stick to lowercase resolve() or keep query() on 1.x until you move. Reference docs and public issue threads both point here as the steady path.
Keep Your DNS Lookups Stable
Bottom line: fix the name, align the version, and wrap the call so the rest of your code never needs to care. A short session prints the version and import path, a search replaces any stray .Resolve(, and a pin locks the behavior. With that in place, your lookups will stay predictable across laptops, servers, and CI runners.
