urllib3 breaking changes
Every breaking API change we have recorded in urllib3 on PyPI: 37 breaking changes in 6 versions. Below are its newest 6 versions, removals and renames first, each with its source.
Newest change September 15, 2026

On this page
2.8.0
- Behavior changed
Percent-encoded SOCKS proxy credentials are now decoded before authentication. Credentials that were sent encoded will now be sent decoded. github.com - Behavior changed
Explicit :0 ports are kept in URL parsing, pool selection, proxy configuration and connection_from_url() rather than replaced with 80 or 443. github.com - Behavior changed
Obsolete folded header lines are now replaced with spaces, so raw CRLF sequences no longer appear in header values such as Set-Cookie. github.com - Behavior changed
assert_fingerprint
A fingerprint of supported length with non-hex characters now raises SSLError. Code catching binascii.Error must catch SSLError instead. github.com - Behavior changed
ConnectionPool.pool
LifoQueue is now resolved from the queue module after the ConnectionPool is instantiated, so late monkey-patching such as by gevent takes effect. github.com - Behavior changed
HTTPConnectionPool.urlopen
URL fragments are now removed from absolute request targets before sending, including through HTTP proxy forwarding. github.com - Behavior changed
HTTPSConnection.connect
Destination client certificates and identity checks no longer apply to HTTPS forwarding proxies. Configure proxy certificates in proxy_ssl_context and use proxy_assert_hostname or proxy_assert_fingerprint for identity checks. github.com - Behavior changed
is_ipaddress
Hex, octal and integer IPv4 forms are now detected as IP addresses, so certificate verification uses IP mode for them. github.com - Behavior changed
parse_url
Hosts with raw spaces, control characters or malformed percent-encodings are now rejected, and percent-encoded unreserved characters are decoded during normalization. github.com - Behavior changed
UnrewindableBodyError
Retrying a request whose body supports tell() but not seek() now raises UnrewindableBodyError instead of ValueError. Code catching ValueError must catch UnrewindableBodyError. github.com
And 4 more in this version.
2.7.0
- Removed
PyPy3.10 is no longer supported. Users on PyPy3.10 must upgrade their interpreter. github.com - Removed
Python 3.9 is no longer supported. Users on Python 3.9 must upgrade their interpreter. github.com - Removed
urllib3.util.ssl_.VERIFY_X509_PARTIAL_CHAIN
urllib3.util.ssl_.VERIFY_X509_PARTIAL_CHAIN was removed in urllib3 2.7.0 pypi.org - Behavior changed
Existing deprecation notices are now emitted as FutureWarning, so code that filters or expects DeprecationWarning may behave differently. github.com - Configuration changed
Environments with an older pyOpenSSL must upgrade to version 19.0.0 or later. github.com - Signature changed
urllib3.BaseHTTPResponse.readinto
Was def readinto(self, b: bytearray) -> int; now def readinto(self, b: bytearray | memoryview[int]) -> int. pypi.org
2.6.3
- Behavior changed
Retry handling now treats Retry-After values greater than 6 hours as 6 hours by default. Code that relied on longer waits must configure its retry behavior explicitly. github.com - Signature changed
urllib3.Retry.__init__
Was def __init__(self, total: bool | int | None = 10, connect: int | None = None, read: int | None = None, redirect: bool | int | None = None, status: int | None = None, other: int | None = None, allowed_methods: typing.Collection[str] |... pypi.org
2.6.0
- Removed
urllib3.BaseHTTPResponse.getheader
HTTPResponse.getheader(name, default) is gone. Use HTTPResponse.headers.get(name, default) instead. pypi.org - Removed
urllib3.BaseHTTPResponse.getheaders
HTTPResponse.getheaders() is gone. Use the HTTPResponse.headers attribute instead. pypi.org - Behavior changed
Responses with more than 5 chained Content-Encoding values are now refused during decoding. Code that relies on longer chains must change. github.com - Configuration changed
On Python 3.13 and before, the zstd extra now installs backports.zstd instead of zstandard. github.com - Signature changed
urllib3.connectionpool.MaxRetryError.__init__
Was def __init__(self, pool: ConnectionPool, url: str, reason: Exception | None = None) -> None; now def __init__(self, pool: ConnectionPool, url: str | None, reason: Exception | None = None) -> None. pypi.org - Signature changed
urllib3.exceptions.RequestError.__init__
Was def __init__(self, pool: ConnectionPool, url: str, message: str) -> None; now def __init__(self, pool: ConnectionPool, url: str | None, message: str) -> None. pypi.org - Signature changed
urllib3.response.BytesQueueBuffer.buffer
Was buffer: typing.Deque[bytes]; now buffer: typing.Deque[bytes | memoryview[bytes]]. pypi.org - Signature changed
urllib3.response.ContentDecoder
The ContentDecoder API changed, so custom decompressors must be updated to match the new interface. github.com - Signature changed
urllib3.response.ContentDecoder.decompress
Was def decompress(self, data: bytes) -> bytes; now def decompress(self, data: bytes, max_length: int = -1) -> bytes. pypi.org
2.5.0
- Behavior changed
In the Node.js runtime, redirects are now handled by urllib3 rather than the runtime. Check code that depends on the previous redirect behavior. github.com - Behavior changed
When retries is passed, pool managers now control redirects themselves. Check code that relies on the previous redirect handling. github.com - Behavior changed
HTTPResponse.shutdown
Calling shutdown on a response whose connection was already released to the pool now raises an exception. Code that calls it in this state must handle the exception. github.com
2.4.0
- Default changed
create_urllib3_context
On Python 3.13 and later, create_urllib3_context now defaults to VERIFY_X509_PARTIAL_CHAIN and VERIFY_X509_STRICT. Pass the verify_flags option to override these defaults. github.com - Signature changed
urllib3.connection.create_urllib3_context
Was def create_urllib3_context(ssl_version: int | None = None, cert_reqs: int | None = None, options: int | None = None, ciphers: str | None = None, ssl_minimum_version: int | None = None, ssl_maximum_version: int | None = None) ->... pypi.org - Signature changed
urllib3.util.create_urllib3_context
Was def create_urllib3_context(ssl_version: int | None = None, cert_reqs: int | None = None, options: int | None = None, ciphers: str | None = None, ssl_minimum_version: int | None = None, ssl_maximum_version: int | None = None) ->... pypi.org
Check your code
These are the changes. To see which of them reach your code, scan a public repository, or have your coding agent call check_code with your manifest or lockfile over MCP. The API reads every change in every version, not only the newest. On Team and up, a fix pull request opens for the changes that reach a connected repository. Nothing merges or deploys.

Put your code on continuous management.
Scan a public repository now, or give your agent one line.
See how out of date your code is.
Tell your agent what changed since it was trained.
claude mcp add --transport http since https://api.since.dev/mcp