Jump to solution
Verify

The Fix

Upgrade to version 0.25.0 or later.

Based on closed Kludex/starlette issue #2032 · PR/commit linked

Jump to Verify Open PR/Commit
@@ -293,7 +293,7 @@ def test_file_response_with_inline_disposition(tmpdir, test_client_factory): def test_set_cookie(test_client_factory, monkeypatch): # Mock time used as a reference for `Expires` by stdlib `SimpleCookie`. - mocked_now = dt.datetime(2100, 1, 22, 12, 0, 0, tzinfo=dt.timezone.utc) + mocked_now = dt.datetime(2037, 1, 22, 12, 0, 0, tzinfo=dt.timezone.utc) monkeypatch.setattr(time, "time", lambda: mocked_now.timestamp())
repro.py
[ 40s] ___________________ test_expires_on_set_cookie[asyncio-int] ____________________ [ 40s] [ 40s] test_client_factory = functools.partial(<class 'starlette.testclient.TestClient'>, backend='asyncio', backend_options={}) [ 40s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0xf38e7988> [ 40s] expires = 10 [ 40s] [ 40s] @pytest.mark.parametrize( [ 40s] "expires", [ 40s] [ [ 40s] pytest.param( [ 40s] dt.datetime(2100, 1, 22, 12, 0, 10, tzinfo=dt.timezone.utc), id="datetime" [ 40s] ), [ 40s] pytest.param("Fri, 22 Jan 2100 12:00:10 GMT", id="str"), [ 40s] pytest.param(10, id="int"), [ 40s] ], [ 40s] ) [ 40s] def test_expires_on_set_cookie(test_client_factory, monkeypatch, expires): [ 40s] # Mock time used as a reference for `Expires` by stdlib `SimpleCookie`. [ 40s] mocked_now = dt.datetime(2100, 1, 22, 12, 0, 0, tzinfo=dt.timezone.utc) [ 40s] monkeypatch.setattr(time, "time", lambda: mocked_now.timestamp()) [ 40s] [ 40s] async def app(scope, receive, send): [ 40s] response = Response("Hello, world!", media_type="text/plain") [ 40s] response.set_cookie("mycookie", "myvalue", expires=expires) [ 40s] await response(scope, receive, send) [ 40s] [ 40s] client = test_client_factory(app) [ 40s] > response = client.get("/") [ 40s] [ 40s] tests/test_responses.py:345: [ 40s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [ 40s] starlette/testclient.py:492: in get [ 40s] return super().get( [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:1045: in get [ 40s] return self.request( [ 40s] starlette/testclient.py:458: in request [ 40s] return super().request( [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:821: in request [ 40s] return self.send(request, auth=auth, follow_redirects=follow_redirects) [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:908: in send [ 40s] response = self._send_handling_auth( [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:936: in _send_handling_auth [ 40s] response = self._send_handling_redirects( [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:973: in _send_handling_redirects [ 40s] response = self._send_single_request(request) [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:1009: in _send_single_request [ 40s] response = transport.handle_request(request) [ 40s] starlette/testclient.py:337: in handle_request [ 40s] raise exc [ 40s] starlette/testclient.py:334: in handle_request [ 40s] portal.call(self.app, scope, receive, send) [ 40s] /usr/lib/python3.8/site-packages/anyio/from_thread.py:283: in call [ 40s] return cast(T_Retval, self.start_task_soon(func, *args).result()) [ 40s] /usr/lib/python3.8/concurrent/futures/_base.py:437: in result [ 40s] return self.__get_result() [ 40s] /usr/lib/python3.8/concurrent/futures/_base.py:389: in __get_result [ 40s] raise self._exception [ 40s] /usr/lib/python3.8/site-packages/anyio/from_thread.py:219: in _call_func [ 40s] retval = await retval [ 40s] tests/test_responses.py:341: in app [ 40s] response.set_cookie("mycookie", "myvalue", expires=expires) [ 40s] starlette/responses.py:140: in set_cookie [ 40s] cookie_val = cookie.output(header="").strip() [ 40s] /usr/lib/python3.8/http/cookies.py:502: in output ... (truncated) ...
verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.
fix.md
Option A — Upgrade to fixed release\nUpgrade to version 0.25.0 or later.\nWhen NOT to use: This fix is not applicable if tests are expected to run on platforms supporting dates beyond 2037.\n\n

Why This Fix Works in Production

  • Trigger: OverflowError: timestamp out of range for platform time_t
  • Mechanism: Tests failed on 32-bit platforms due to date overflow in time_t
  • Why the fix works: Fixes tests that were failing on 32-bit architectures by adjusting the expiration date for cookies to a maximum year value of 2037. (first fixed release: 0.25.0).
Production impact:
  • If left unfixed, this can cause silent data inconsistencies that propagate (bad cache entries, incorrect downstream decisions).

Why This Breaks in Prod

  • Shows up under Python 3.8 in real deployments (not just unit tests).
  • Tests failed on 32-bit platforms due to date overflow in time_t
  • Surfaces as: OverflowError: timestamp out of range for platform time_t

Proof / Evidence

  • GitHub issue: #2032
  • Fix PR: https://github.com/encode/starlette/pull/2033
  • First fixed release: 0.25.0
  • Reproduced locally: No (not executed)
  • Last verified: 2026-02-09
  • Confidence: 0.85
  • Did this fix it?: Yes (upstream fix exists)
  • Own content ratio: 0.38

Discussion

High-signal excerpts from the issue thread (symptoms, repros, edge-cases).

“> We just need to change the year? Yeah, that will do it.”
@kraptor · 2023-02-11 · source
“Would you like to open a PR? Since you can verify the date it will work on those OSs.”
@Kludex · 2023-02-11 · source
“Closed by https://github.com/encode/starlette/pull/2033”
@Kludex · 2023-02-11 · source
“Isn't the test wrong anyway? Shouldn't set-cookie be automatically propagated to subsequent requests made by the TestClient? I had to work around this limitation in…”
@cglacet · 2023-02-21 · source

Failure Signature (Search String)

  • OverflowError: timestamp out of range for platform time_t

Error Message

Stack trace
error.txt
Error Message ------------- OverflowError: timestamp out of range for platform time_t

Minimal Reproduction

repro.py
[ 40s] ___________________ test_expires_on_set_cookie[asyncio-int] ____________________ [ 40s] [ 40s] test_client_factory = functools.partial(<class 'starlette.testclient.TestClient'>, backend='asyncio', backend_options={}) [ 40s] monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0xf38e7988> [ 40s] expires = 10 [ 40s] [ 40s] @pytest.mark.parametrize( [ 40s] "expires", [ 40s] [ [ 40s] pytest.param( [ 40s] dt.datetime(2100, 1, 22, 12, 0, 10, tzinfo=dt.timezone.utc), id="datetime" [ 40s] ), [ 40s] pytest.param("Fri, 22 Jan 2100 12:00:10 GMT", id="str"), [ 40s] pytest.param(10, id="int"), [ 40s] ], [ 40s] ) [ 40s] def test_expires_on_set_cookie(test_client_factory, monkeypatch, expires): [ 40s] # Mock time used as a reference for `Expires` by stdlib `SimpleCookie`. [ 40s] mocked_now = dt.datetime(2100, 1, 22, 12, 0, 0, tzinfo=dt.timezone.utc) [ 40s] monkeypatch.setattr(time, "time", lambda: mocked_now.timestamp()) [ 40s] [ 40s] async def app(scope, receive, send): [ 40s] response = Response("Hello, world!", media_type="text/plain") [ 40s] response.set_cookie("mycookie", "myvalue", expires=expires) [ 40s] await response(scope, receive, send) [ 40s] [ 40s] client = test_client_factory(app) [ 40s] > response = client.get("/") [ 40s] [ 40s] tests/test_responses.py:345: [ 40s] _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ [ 40s] starlette/testclient.py:492: in get [ 40s] return super().get( [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:1045: in get [ 40s] return self.request( [ 40s] starlette/testclient.py:458: in request [ 40s] return super().request( [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:821: in request [ 40s] return self.send(request, auth=auth, follow_redirects=follow_redirects) [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:908: in send [ 40s] response = self._send_handling_auth( [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:936: in _send_handling_auth [ 40s] response = self._send_handling_redirects( [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:973: in _send_handling_redirects [ 40s] response = self._send_single_request(request) [ 40s] /usr/lib/python3.8/site-packages/httpx/_client.py:1009: in _send_single_request [ 40s] response = transport.handle_request(request) [ 40s] starlette/testclient.py:337: in handle_request [ 40s] raise exc [ 40s] starlette/testclient.py:334: in handle_request [ 40s] portal.call(self.app, scope, receive, send) [ 40s] /usr/lib/python3.8/site-packages/anyio/from_thread.py:283: in call [ 40s] return cast(T_Retval, self.start_task_soon(func, *args).result()) [ 40s] /usr/lib/python3.8/concurrent/futures/_base.py:437: in result [ 40s] return self.__get_result() [ 40s] /usr/lib/python3.8/concurrent/futures/_base.py:389: in __get_result [ 40s] raise self._exception [ 40s] /usr/lib/python3.8/site-packages/anyio/from_thread.py:219: in _call_func [ 40s] retval = await retval [ 40s] tests/test_responses.py:341: in app [ 40s] response.set_cookie("mycookie", "myvalue", expires=expires) [ 40s] starlette/responses.py:140: in set_cookie [ 40s] cookie_val = cookie.output(header="").strip() [ 40s] /usr/lib/python3.8/http/cookies.py:502: in output ... (truncated) ...

Environment

  • Python: 3.8

What Broke

Tests for cookie expiration failed, causing CI pipeline failures on 32-bit architectures.

Why It Broke

Tests failed on 32-bit platforms due to date overflow in time_t

Fix Options (Details)

Option A — Upgrade to fixed release Safe default (recommended)

Upgrade to version 0.25.0 or later.

When NOT to use: This fix is not applicable if tests are expected to run on platforms supporting dates beyond 2037.

Use when you can deploy the upstream fix. It is usually lower-risk than long-lived workarounds.

Fix reference: https://github.com/encode/starlette/pull/2033

First fixed release: 0.25.0

Last verified: 2026-02-09. Validate in your environment.

Get updates

We publish verified fixes weekly. No spam.

Subscribe

When NOT to Use This Fix

  • This fix is not applicable if tests are expected to run on platforms supporting dates beyond 2037.

Verify Fix

verify
Re-run the minimal reproduction on your broken version, then apply the fix and re-run.

Did This Fix Work in Your Case?

Quick signal helps us prioritize which fixes to verify and improve.

Prevention

  • Capture the exact failing error string in logs and tests so you can reproduce via a minimal script.
  • Pin production dependencies and upgrade only with a reproducible test that hits the failing path.

Version Compatibility Table

VersionStatus
0.25.0 Fixed

Related Issues

No related fixes found.

Sources

We don’t republish the full GitHub discussion text. Use the links above for context.