---
title: "h2 Breaking Changes on PyPI | Since.dev"
description: "What each h2 release removed, renamed or changed: 70 breaking changes in 3 versions on PyPI, each with its source."
canonical_url: https://since.dev/packages/pypi/h2
last_updated: 2026-08-03
---

# h2 breaking changes

Every breaking API change we have recorded in h2 on PyPI: 70 breaking changes in 3 versions. Below are its newest 3 versions, removals and renames first, each with its source.

Newest change August 3, 2026

## 4.4.1

1 breaking change, first published August 3, 2026.

- **Behavior changed**  

Requests containing more than one Host header are now rejected. Users who send duplicate Host headers must send a single Host header instead. [github.com](https://github.com/python-hyper/h2/blob/v4.4.1/CHANGELOG.rst)

## 4.4.0

25 breaking changes, first published July 23, 2026.

- **Removed**  

Python 3.9 is no longer supported, so code running on it must move to a newer Python version. [github.com](https://github.com/python-hyper/h2/blob/v4.4.0/CHANGELOG.rst)
- **Removed**  

PyPy 3.9 is no longer supported, so code running on it must move to a newer PyPy version. [github.com](https://github.com/python-hyper/h2/blob/v4.4.0/CHANGELOG.rst)
- **Behavior changed**  

Non-zero SETTINGS_ENABLE_PUSH values received from servers are now rejected instead of accepted. [github.com](https://github.com/python-hyper/h2/blob/v4.4.0/CHANGELOG.rst)
- **Behavior changed**  

content-length values are now parsed according to the RFC 9110 grammar for numbers (1\*DIGIT), which may reject values previously accepted. [github.com](https://github.com/python-hyper/h2/blob/v4.4.0/CHANGELOG.rst)
- **Behavior changed**  

Duplicate content-length headers with conflicting values now raise ProtocolError instead of the first value being silently accepted. [github.com](https://github.com/python-hyper/h2/blob/v4.4.0/CHANGELOG.rst)
- **Behavior changed**  

Ordinary CONNECT requests now require :method=CONNECT and :authority and forbid :scheme and :path; extended CONNECT requires :scheme, :path, :authority and :protocol. [github.com](https://github.com/python-hyper/h2/blob/v4.4.0/CHANGELOG.rst)
- **Behavior changed** `Stream.end_stream`  

Stream.end_stream() now raises NoSuchStreamError or StreamClosedError instead of a generic KeyError, so code catching KeyError must catch the new exceptions. [github.com](https://github.com/python-hyper/h2/blob/v4.4.0/CHANGELOG.rst)
- **Signature changed**  

Emitted events are now Python dataclasses with required constructor arguments, so instantiating them without arguments no longer works. [github.com](https://github.com/python-hyper/h2/blob/v4.4.0/CHANGELOG.rst)
- **Signature changed** `h2.connection.FrameBuffer.add_data`  

Was def add_data(self, data: bytes) -> None; now def add_data(self, data: Buffer) -> None. [pypi.org](https://pypi.org/project/h2/4.4.0/)
- **Signature changed** `h2.connection.H2Connection.receive_data`  

Was def receive_data(self, data: bytes) -> list\[Event\]; now def receive_data(self, data: Buffer) -> list\[Event\]. [pypi.org](https://pypi.org/project/h2/4.4.0/)

And 15 more in this version.

## 4.3.0

44 breaking changes, first published August 23, 2025.

- **Removed** `h2.connection.FrameBuffer.data`  

FrameBuffer.data was removed in h2 4.3.0 [pypi.org](https://pypi.org/project/h2/4.3.0/)
- **Removed** `h2.utilities.UPPER_RE`  

h2.utilities.UPPER_RE was removed in h2 4.3.0 [pypi.org](https://pypi.org/project/h2/4.3.0/)
- **Behavior changed**  

Header names and values with characters illegal under RFC 9113 section 8.2.1 are now rejected, so some previously valid requests or responses may be blocked. Use the validate_inbound_headers config option if needed. [github.com](https://github.com/python-hyper/h2/blob/v4.3.0/CHANGELOG.rst)
- **Signature changed** `h2.connection.InformationalResponseReceived.__init__`  

Was def \_\_init\_\_(self) -> None; now def \_\_init\_\_(self, stream_id: int, headers: list\[Header\] = \_LAZY_INIT, priority_updated: PriorityUpdated | None = None) -> None. [pypi.org](https://pypi.org/project/h2/4.3.0/)
- **Signature changed** `h2.connection.InformationalResponseReceived.headers`  

Was headers: list\[HeaderTuple\] | None; now headers: list\[Header\]. [pypi.org](https://pypi.org/project/h2/4.3.0/)
- **Signature changed** `h2.connection.InformationalResponseReceived.stream_id`  

Was stream_id: int | None; now stream_id: int. [pypi.org](https://pypi.org/project/h2/4.3.0/)
- **Signature changed** `h2.connection.PingAckReceived.__init__`  

Was def \_\_init\_\_(self) -> None; now def \_\_init\_\_(self, ping_data: bytes) -> None. [pypi.org](https://pypi.org/project/h2/4.3.0/)
- **Signature changed** `h2.connection.PingAckReceived.ping_data`  

Was ping_data: bytes | None; now ping_data: bytes. [pypi.org](https://pypi.org/project/h2/4.3.0/)
- **Signature changed** `h2.connection.PingReceived.__init__`  

Was def \_\_init\_\_(self) -> None; now def \_\_init\_\_(self, ping_data: bytes) -> None. [pypi.org](https://pypi.org/project/h2/4.3.0/)
- **Signature changed** `h2.connection.PingReceived.ping_data`  

Was ping_data: bytes | None; now ping_data: bytes. [pypi.org](https://pypi.org/project/h2/4.3.0/)

And 34 more in this version.

## Check your code

These are the changes. To see which of them reach your code, [scan a public repository](https://since.dev/scan.md), or have your coding agent call `check_code` with your manifest or lockfile over [MCP](https://since.dev/docs.md#mcp). [The API](https://since.dev/docs.md#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.

[Scan a repository](https://since.dev/scan.md). Any public GitHub repository. No sign-in.

### Tell your agent what changed since it was trained.

`claude mcp add --transport http since https://api.since.dev/mcp`

---

Every page on this site as Markdown: https://since.dev/sitemap.md. For agents: https://since.dev/llms.txt.
