Skip to content

Wait for positive HTTP/2 flow-control credit when stream window goes negative#935

Merged
Kludex merged 5 commits into
pydantic:mainfrom
mbeijen:fix/http2-negative-flow-control-window
May 15, 2026
Merged

Wait for positive HTTP/2 flow-control credit when stream window goes negative#935
Kludex merged 5 commits into
pydantic:mainfrom
mbeijen:fix/http2-negative-flow-control-window

Conversation

@mbeijen
Copy link
Copy Markdown
Contributor

@mbeijen mbeijen commented May 14, 2026

Summary

  • Fixes _wait_for_outgoing_flow in httpcore2's HTTP/2 implementation to wait while the available flow is non-positive, not just exactly zero.
  • Per RFC 7540 §6.9.2, when a peer sends a SETTINGS frame that reduces INITIAL_WINDOW_SIZE, existing stream send windows are adjusted by the delta and may become negative. With the previous while flow == 0 guard, a negative value would pass straight through and h2 would raise LocalProtocolError("Cannot send N bytes, flow control window is -M") on the next send_data call.
  • Switching to while flow <= 0 keeps the stream parked until WINDOW_UPDATE frames restore positive credit.

Refs: encode/httpcore#1082, encode/httpx#3601.

Test plan

  • New test test_http2_connection_with_negative_flow_control_window added in both tests/httpcore2/_async/test_http2.py and tests/httpcore2/_sync/test_http2.py. Reproduces the bug via a mock stream that sends a window-reducing SETTINGS frame after the default 65535-byte window is exhausted, then provides WINDOW_UPDATE credit to finish the upload.
  • New tests fail without the source-code change (verified locally) and pass with it.
  • Full tests/httpcore2/_async/test_http2.py and tests/httpcore2/_sync/test_http2.py pass — 33/33.
  • Top-level scripts/check passes (format / mypy / ruff).

🤖 Generated with Claude Code

mbeijen and others added 5 commits May 14, 2026 10:07
`_wait_for_outgoing_flow` previously waited only while the available
flow was exactly zero. Per RFC 7540 §6.9.2, when a peer sends a
SETTINGS frame that reduces INITIAL_WINDOW_SIZE, every existing
stream send window is adjusted by the delta and may become negative.
With the `while flow == 0` guard, a negative window passed straight
through and h2 raised `LocalProtocolError("Cannot send N bytes, flow
control window is -M")` on the next send_data call.

Switching the guard to `while flow <= 0` keeps the stream parked
until WINDOW_UPDATE frames restore positive credit.

Refs: encode/httpcore#1082
Refs: encode/httpx#3601

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@Kludex Kludex changed the title Fix HTTP/2 send when flow-control window is negative Wait for positive HTTP/2 flow-control credit when stream window goes negative May 15, 2026
Copy link
Copy Markdown
Member

@Kludex Kludex left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@Kludex Kludex merged commit 86a3b71 into pydantic:main May 15, 2026
8 checks passed
@Kludex Kludex mentioned this pull request May 15, 2026
1 task
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants