httpcore

raw JSON →
1.0.9 verified Tue May 12 auth: no python install: verified quickstart: stale

httpcore is a minimal, low-level HTTP/1.1 and HTTP/2 client library for Python, intended as a transport layer for higher-level clients such as httpx. It provides synchronous and (optionally) asynchronous connection pooling, SOCKS proxy support, streaming responses, and a 'trace' extension for request lifecycle introspection. Current stable version is 1.0.9 (April 2025). The project follows SEMVER and releases several times per year.

pip install httpcore
error ModuleNotFoundError: No module named 'httpcore'
cause The 'httpcore' library is not installed in your current Python environment.
fix
Install the library using pip: pip install httpcore.
error AttributeError: module 'httpcore' has no attribute 'TimeoutException'
cause This error typically occurs due to version incompatibility between `httpx` (which uses `httpcore`) and `httpcore`, where `httpx` expects an attribute that is missing or has been moved in the installed `httpcore` version.
fix
Upgrade both httpx and httpcore to their latest compatible versions: pip install --upgrade httpx httpcore. If issues persist, try pinning to a known stable httpx version that is compatible with your httpcore installation (e.g., pip install httpx==0.19.0).
error AttributeError: module 'httpcore' has no attribute 'NetworkBackend'
cause This `AttributeError` arises from changes in the `httpcore` package, specifically when an older version of the library attempts to access the `NetworkBackend` attribute which was removed or renamed in newer updates.
fix
Upgrade your httpcore package to version 0.15.0 or higher: pip install --upgrade httpcore.
error httpcore.ConnectError: [Errno 111] Connection refused
cause This error indicates that the client attempted to establish a connection to a server, but the server actively refused the connection. This can be due to the server being offline, a firewall blocking the connection, or the service not running on the specified host and port.
fix
Verify that the target server is running, reachable, and listening on the correct IP address and port. Check any firewalls or network configurations that might be blocking the connection.
error httpcore.ProxyError: 407 Proxy Authentication Required
cause This error means that the proxy server requires authentication credentials, but they were not provided or were incorrect.
fix
Ensure that your proxy configuration includes the correct authentication credentials (username and password). For httpx (which uses httpcore), this can be done by providing them in the proxy URL, e.g., proxies = {'all://': 'http://user:password@myproxy.com:8080'}.
breaking CVE-2025-43859 (GHSA-vqfr-h8mv-ghfj): h11 <=0.15.0 accepts malformed Chunked-Encoding bodies enabling HTTP request smuggling (CVSS 9.1). httpcore <1.0.9 pulls in vulnerable h11. Upgrade to httpcore 1.0.9+ which requires h11>=0.16.0.
fix pip install 'httpcore>=1.0.9' to pull in h11>=0.16.0 which fixes CVE-2025-43859.
breaking Async support is NOT included in the default install since 1.0.0. Importing or instantiating AsyncConnectionPool without the async extras raises a RuntimeError at runtime, not at import time.
fix Install the appropriate extra: pip install 'httpcore[asyncio]' or pip install 'httpcore[trio]'.
gotcha Response headers (and request headers) are List[Tuple[bytes, bytes]], not a string-keyed dict. Comparing or accessing headers with plain strings will silently fail or raise a TypeError.
fix Decode header names/values explicitly: [(k.decode(), v.decode()) for k, v in response.headers], or use a higher-level client like httpx which handles decoding for you.
gotcha httpcore.request() and httpcore.stream() are top-level convenience helpers that open a new connection on every call. Using them in production code bypasses connection pooling entirely, causing a new TCP+TLS handshake per request.
fix Instantiate httpcore.ConnectionPool() (or AsyncConnectionPool()) and reuse it across requests, ideally as a context manager.
breaking The pre-1.0 class names SyncConnectionPool and SyncHTTPProxy were removed. Any code importing these names directly will raise an ImportError.
fix Replace SyncConnectionPool with ConnectionPool and SyncHTTPProxy with HTTPProxy.
gotcha Timeouts are passed via the request extensions dict, not as top-level kwargs: httpcore.request('GET', url, extensions={'timeout': {'connect': 5.0, 'read': 10.0}}). Passing timeout= as a keyword argument has no effect and is silently ignored.
fix Always use extensions={'timeout': {'connect': N, 'read': N, 'write': N, 'pool': N}} to configure timeouts.
gotcha response.content is only available after the full body has been read. When using httpcore.stream() or iterating response.iter_stream(), accessing response.content before calling response.read() raises an error.
fix Call response.read() inside the stream context block before accessing response.content, or use httpcore.request() which reads the body automatically.
pip install 'httpcore[asyncio]'
pip install 'httpcore[trio]'
pip install 'httpcore[http2]'
pip install 'httpcore[socks]'
pip install 'httpcore[asyncio,http2,socks]'
python os / libc variant status wheel install import disk
3.10 alpine (musl) asyncio,http2,socks - - 1.31s 22.6M
3.10 alpine (musl) asyncio - - 0.25s 21.3M
3.10 alpine (musl) http2 - - 1.08s 20.2M
3.10 alpine (musl) socks - - 0.14s 19.1M
3.10 alpine (musl) trio - - 0.42s 25.0M
3.10 alpine (musl) httpcore - - 0.14s 19.0M
3.10 slim (glibc) asyncio,http2,socks - - 1.85s 23M
3.10 slim (glibc) asyncio - - 0.18s 22M
3.10 slim (glibc) http2 - - 1.76s 21M
3.10 slim (glibc) socks - - 0.10s 20M
3.10 slim (glibc) trio - - 0.32s 25M
3.10 slim (glibc) httpcore - - 0.09s 19M
3.11 alpine (musl) asyncio,http2,socks - - 0.94s 24.6M
3.11 alpine (musl) asyncio - - 0.40s 23.3M
3.11 alpine (musl) http2 - - 0.74s 22.1M
3.11 alpine (musl) socks - - 0.24s 21.1M
3.11 alpine (musl) trio - - 0.53s 27.7M
3.11 alpine (musl) httpcore - - 0.23s 21.0M
3.11 slim (glibc) asyncio,http2,socks - - 0.76s 25M
3.11 slim (glibc) asyncio - - 0.32s 24M
3.11 slim (glibc) http2 - - 0.63s 23M
3.11 slim (glibc) socks - - 0.21s 22M
3.11 slim (glibc) trio - - 0.46s 28M
3.11 slim (glibc) httpcore - - 0.18s 21M
3.12 alpine (musl) asyncio,http2,socks - - 1.02s 16.4M
3.12 alpine (musl) asyncio - - 0.63s 15.1M
3.12 alpine (musl) http2 - - 0.62s 14.0M
3.12 alpine (musl) socks - - 0.20s 12.9M
3.12 alpine (musl) trio - - 0.46s 19.2M
3.12 alpine (musl) httpcore - - 0.20s 12.8M
3.12 slim (glibc) asyncio,http2,socks - - 1.05s 17M
3.12 slim (glibc) asyncio - - 0.59s 16M
3.12 slim (glibc) http2 - - 0.67s 14M
3.12 slim (glibc) socks - - 0.23s 13M
3.12 slim (glibc) trio - - 0.47s 20M
3.12 slim (glibc) httpcore - - 0.20s 13M
3.13 alpine (musl) asyncio,http2,socks - - 0.72s 15.7M
3.13 alpine (musl) asyncio - - 0.28s 14.4M
3.13 alpine (musl) http2 - - 0.55s 13.6M
3.13 alpine (musl) socks - - 0.20s 12.6M
3.13 alpine (musl) trio - - 0.48s 18.9M
3.13 alpine (musl) httpcore - - 0.18s 12.5M
3.13 slim (glibc) asyncio,http2,socks - - 0.75s 16M
3.13 slim (glibc) asyncio - - 0.28s 15M
3.13 slim (glibc) http2 - - 0.59s 14M
3.13 slim (glibc) socks - - 0.20s 13M
3.13 slim (glibc) trio - - 0.47s 19M
3.13 slim (glibc) httpcore - - 0.18s 13M
3.9 alpine (musl) asyncio,http2,socks - - 0.32s 21.7M
3.9 alpine (musl) asyncio - - 0.25s 20.6M
3.9 alpine (musl) http2 - - 0.17s 19.4M
3.9 alpine (musl) socks - - 0.14s 18.6M
3.9 alpine (musl) trio - - 0.39s 24.3M
3.9 alpine (musl) httpcore - - 0.13s 18.4M
3.9 slim (glibc) asyncio,http2,socks - - 0.27s 22M
3.9 slim (glibc) asyncio - - 0.23s 21M
3.9 slim (glibc) http2 - - 0.15s 20M
3.9 slim (glibc) socks - - 0.14s 19M
3.9 slim (glibc) trio - - 0.37s 25M
3.9 slim (glibc) httpcore - - 0.11s 19M

Demonstrates the one-off request helper, the recommended ConnectionPool pattern, streaming, and async usage.

import httpcore

# One-off request (no connection reuse)
response = httpcore.request('GET', 'https://httpbin.org/get')
print(response.status)   # int, e.g. 200
# Headers are List[Tuple[bytes, bytes]] — decode explicitly
for name, value in response.headers:
    print(name.decode(), value.decode())
print(response.content)  # bytes

# Production pattern: reuse a ConnectionPool
with httpcore.ConnectionPool() as http:
    r = http.request('GET', 'https://httpbin.org/get')
    print(r.status)

# Streaming large response
with httpcore.stream('GET', 'https://httpbin.org/stream-bytes/1024') as r:
    for chunk in r.iter_stream():
        pass  # process chunk (bytes)

# Async (requires: pip install 'httpcore[asyncio]')
import asyncio

async def main():
    async with httpcore.AsyncConnectionPool() as http:
        r = await http.request('GET', 'https://httpbin.org/get')
        print(r.status)

asyncio.run(main())