Install & Compatibility
Where this runs
tested against v5.0.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.082s · 20.4MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 2.2s · import 0.076s · 21MB
19MB installed
● package 19MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
This quickstart demonstrates how to perform asynchronous DNS queries for A and MX records using `pycares`. It sets up a `Channel` and makes two queries with a shared callback function. A basic `select`-based loop is used to process file descriptors and handle the asynchronous responses. In a production environment, `pycares` is typically integrated with a more robust event loop like `asyncio` (via `aiodns`), `Tornado`, or `Gevent`.
import pycares
import socket
def callback(result, error):
if error:
print(f"Error: {error}")
return
if result:
for record in result.answer:
if record.type == pycares.QUERY_TYPE_A:
print(f"A record for {record.name}: {record.data.addr}")
elif record.type == pycares.QUERY_TYPE_AAAA:
print(f"AAAA record for {record.name}: {record.data.addr}")
elif record.type == pycares.QUERY_TYPE_MX:
print(f"MX record for {record.name}: priority={record.data.priority}, exchange={record.data.exchange}")
# Add other record types as needed
else:
print("No records found.")
# Using a simple select-based event loop
channel = pycares.Channel(timeout=5.0)
# Query for A records
channel.query("google.com", pycares.QUERY_TYPE_A, callback=callback)
# Query for MX records
channel.query("example.com", pycares.QUERY_TYPE_MX, callback=callback)
# Basic event loop processing
while True:
read_fds, write_fds = channel.getsockname()
if not read_fds and not write_fds:
break
# In a real application, use an actual event loop (e.g., asyncio, Tornado, Gevent)
# For this simple example, we block briefly
try:
rlist, wlist, xlist = socket.select(read_fds, write_fds, [], 1.0)
except socket.error as e:
print(f"Socket error in select: {e}")
break
channel.process_fd(rlist, wlist)
Debug
Known issues
breakingThe DNS query results API was completely rewritten in v5.0.0. Results are now returned as structured dataclasses (`DNSResult`, `DNSRecord`, and specific `RecordData` types like `ARecordData`, `MXRecordData`, etc.) instead of a list of record-specific objects. Existing code accessing results will break.fixUpdate your result parsing logic to expect `DNSResult` objects with `answer`, `authority`, and `additional` sections, and access record data via `record.data.addr`, `record.data.exchange`, etc. Refer to the v5.0.0 migration guide for details.
affects: >=5.0.0
breakingIn v5.0.0, the `Channel` constructor arguments and the `callback` parameter for query methods are now strictly keyword-only. The `event_thread` parameter has also been removed, as event thread mode is now implicit.fixPass all `Channel` constructor arguments (e.g., `timeout`, `flags`, `lookups`) and the `callback` argument to query methods as keyword arguments. Remove any explicit `event_thread` arguments.
affects: >=5.0.0
breakingAs of v5.0.0, TXT record data is returned as bytes instead of strings. This change affects how TXT record content should be handled.fixEnsure your application decodes TXT record data (e.g., `record.data.data.decode('utf-8')`) if string representation is required. affects: >=5.0.0
breakingPycares v5.0.0 switched its build system for the bundled c-ares library to CMake. Building from source now requires CMake version 3.5 or higher to be installed on the system.fixInstall CMake (version 3.5+) on your system before attempting to build `pycares` from source (e.g., `apt-get install cmake` on Debian/Ubuntu, `brew install cmake` on macOS).
affects: >=5.0.0
gotchaImproper management of `pycares.Channel` objects, particularly allowing them to be garbage collected while DNS queries are still pending, can lead to a use-after-free vulnerability, causing a fatal Python interpreter crash.fixEnsure `Channel` objects are explicitly kept alive and properly managed for the entire duration of any pending DNS queries. Implement robust lifecycle management, especially in long-running or highly concurrent applications. Avoid creating `Channel` objects per-request that might be prematurely destroyed.
affects: <=5.0.1 (general concern, specific fixes likely in 5.x)
gotchaDNS queries made by `pycares` are real network operations. Consequently, tests and examples often require active internet access and can be sensitive to network conditions or DNS server configurations, potentially leading to environment-specific failures.fixWhen developing or testing, ensure a stable network connection and a properly configured DNS resolver. Account for network-related errors in your application's error handling for DNS lookups.
affects: All
breakingThe `Channel.getsockname()` method has been removed in v5.0.0. Code relying on this method for manual polling of file descriptors will encounter an AttributeError.fixRemove calls to `Channel.getsockname()`. For integrating `pycares` with custom event loops, refer to the v5.0.0 migration guide for updated methods, typically involving `channel.poll()`, `channel.fd`, or `asyncio` integration.
affects: >=5.0.0
breakingThe `getsockname` method has been removed from the `pycares.Channel` object. This impacts custom event loop integrations that previously relied on `getsockname` to obtain file descriptors for polling.fixThe `getsockname` method on `Channel` objects has been removed. Instead of manually polling file descriptors via `select.select` and `getsockname`, integrate `pycares` with an event loop using `channel.loop()` or by registering `channel.fileno()` with your event loop and calling `channel.handle_event(fd, flag)` when events are ready. Refer to the v5.0.0 migration guide or updated examples for detailed event loop integration.
affects: >=5.0.0
Errors
Common errors & fixes
ERROR: Failed building wheel for pycares
This error typically occurs during installation when required C compilation tools (like `gcc` or `clang`) or Python development headers are missing on the system, preventing the `pycares` C extension from being built.
fixEnsure that your system has the necessary build tools and Python development headers. For Debian/Ubuntu, run: `sudo apt-get update && sudo apt-get install build-essential python3-dev`. For Fedora/RHEL: `sudo dnf groupinstall "Development Tools" && sudo dnf install python3-devel`. For macOS, install Xcode Command Line Tools: `xcode-select --install`. Then, try `pip install pycares` again.
ModuleNotFoundError: No module named 'pycares._cares'
This error indicates that the `pycares` C extension module, `_cares`, was not correctly built or cannot be found by Python, often due to a failed or incomplete installation, or issues within a virtual environment.
fixReinstall `pycares`, potentially forcing a source build to ensure the C extension is properly compiled: `pip install --upgrade --force-reinstall --no-binary pycares pycares`. Ensure all build dependencies mentioned in the previous fix are also installed.
AttributeError: module 'pycares' has no attribute 'ares_query_a_result'
This `AttributeError` arises when a dependent library (such as `aiodns`) attempts to use a function or constant (like `ares_query_a_result` or `QUERY_TYPE_CAA`) that exists in a newer version of `pycares`, but an older, incompatible version of `pycares` is currently installed.
fixUpgrade your `pycares` installation to the latest version or a version compatible with the dependent library's requirements: `pip install --upgrade pycares`.
Fatal Python error: b_from_handle: ffi.from_handle() detected that the address passed points to garbage
This fatal error is a result of a use-after-free vulnerability in `pycares` versions prior to 4.9.0, where a `Channel` object could be garbage collected while active DNS queries were still pending, causing a crash when c-ares attempted to access freed memory for callbacks.
fixUpgrade `pycares` to version 4.9.0 or newer, which includes a fix for this vulnerability: `pip install --upgrade pycares`. It is also recommended to explicitly close `pycares.Channel` objects when done or use them as context managers (e.g., `with pycares.Channel() as channel:`).
Upgrade
Version history
5.0.1latest on PyPI · released Jan 1, 2026
Audit
Dependencies
cffirequiredRequired for the Python C interface; version 1.5.0 or higher is needed for Python < 3.14, and 2.0.0b1 or higher for Python >= 3.14.
idnaoptionalProvides IDNA 2008 encoding support; otherwise, the built-in IDNA 2003 codec is used.
c-aresrequiredThe underlying C library for asynchronous DNS resolution. pycares bundles c-ares by default, but a system-wide c-ares can be used by setting PYCARES_USE_SYSTEM_LIB=1 during build.
cmakerequiredRequired (version >= 3.5) to build pycares from source, as it's used to compile the bundled c-ares library.