Skip to content

Fix has_expired() race on _expire_at under concurrent reuse - #1

Open
kevmo314 wants to merge 1 commit into
masterfrom
fix-has-expired-race
Open

kevmo314 wants to merge 1 commit into
masterfrom
fix-has-expired-race

Conversation

@kevmo314

@kevmo314 kevmo314 commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Summary

has_expired() reads self._expire_at twice:

keepalive_expired = self._expire_at is not None and now > self._expire_at

If another thread starts a request on the connection between the two reads, handle_request() sets _expire_at to None and the comparison raises:

TypeError: '>' not supported between instances of 'float' and 'NoneType'

This is easy to hit on free-threaded Python 3.14t, for example when huggingface_hub downloads files on a thread pool with one shared client. The fix reads _expire_at once, in the HTTP/1.1 and HTTP/2 connections, sync and async. New tests simulate the interleaving; they fail before the change and pass after.

Checklist

  • I understand that this PR may be closed in case there was no previous discussion. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.

@kevmo314
kevmo314 force-pushed the fix-has-expired-race branch from 197e7f5 to 42abea3 Compare October 5, 2026 21:03
has_expired() read self._expire_at twice. Another thread starting a
request on the connection can set it to None between the reads, raising
TypeError. Read it once.
@kevmo314
kevmo314 force-pushed the fix-has-expired-race branch from 42abea3 to de5765c Compare October 5, 2026 21:04
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.

1 participant