Skip to content

stream_with_context does not work with async routes #5774

Description

@nkouevda-patreon

Consider this trivial route + test in app.py:

import flask
from flask import Flask
from flask import Response

import pytest

app = Flask(__name__)


@app.route("/foo")
async def foo():
    def gen():
        yield "bar"

    return Response(flask.stream_with_context(gen()))


def test_foo():
    with app.test_client() as client:
        client.get("/foo")

With the following requirements.txt:

flask[async]==3.1.1
pytest==8.4.1
werkzeug==3.1.3

Running pytest app.py results in:

============================= test session starts ==============================
platform darwin -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /private/tmp/stream_with_context
collected 1 item

app.py F                                                                 [100%]

=================================== FAILURES ===================================
___________________________________ test_foo ___________________________________

    def test_foo():
        with app.test_client() as client:
>           client.get("/foo")

app.py:20:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
venv/lib/python3.12/site-packages/werkzeug/test.py:1162: in get
    return self.open(*args, **kw)
           ^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.12/site-packages/flask/testing.py:235: in open
    response = super().open(
venv/lib/python3.12/site-packages/werkzeug/test.py:1116: in open
    response_parts = self.run_wsgi_app(request.environ, buffered=buffered)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.12/site-packages/werkzeug/test.py:988: in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.12/site-packages/werkzeug/test.py:1264: in run_wsgi_app
    app_rv = app(environ, start_response)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.12/site-packages/flask/app.py:1536: in __call__
    return self.wsgi_app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
venv/lib/python3.12/site-packages/flask/app.py:1527: in wsgi_app
    ctx.pop(error)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <RequestContext 'http://localhost/foo' [GET] of app>, exc = None

    def pop(self, exc: BaseException | None = _sentinel) -> None:  # type: ignore
        """Pops the request context and unbinds it by doing that.  This will
        also trigger the execution of functions registered by the
        :meth:`~flask.Flask.teardown_request` decorator.

        .. versionchanged:: 0.9
           Added the `exc` argument.
        """
        clear_request = len(self._cv_tokens) == 1

        try:
            if clear_request:
                if exc is _sentinel:
                    exc = sys.exc_info()[1]
                self.app.do_teardown_request(exc)

                request_close = getattr(self.request, "close", None)
                if request_close is not None:
                    request_close()
        finally:
            ctx = _cv_request.get()
            token, app_ctx = self._cv_tokens.pop()
>           _cv_request.reset(token)
E           ValueError: <Token var=<ContextVar name='flask.request_ctx' at 0x103cd9a30> at 0x104b23a40> was created in a different Context

venv/lib/python3.12/site-packages/flask/ctx.py:418: ValueError
=========================== short test summary info ============================
FAILED app.py::test_foo - ValueError: <Token var=<ContextVar name='flask.request_ctx' at 0x103cd9a30>...
============================== 1 failed in 0.11s ===============================

Similarly, python -m flask run and then curl http://127.0.0.1:5000/foo results in:

127.0.0.1 - - [15/Jul/2025 13:40:14] "GET /foo HTTP/1.1" 500 -
Error on request:
Traceback (most recent call last):
  File "/private/tmp/stream_with_context/venv/lib/python3.12/site-packages/werkzeug/serving.py", line 370, in run_wsgi
    execute(self.server.app)
  File "/private/tmp/stream_with_context/venv/lib/python3.12/site-packages/werkzeug/serving.py", line 331, in execute
    application_iter = app(environ, start_response)
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/private/tmp/stream_with_context/venv/lib/python3.12/site-packages/flask/app.py", line 1536, in __call__
    return self.wsgi_app(environ, start_response)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/private/tmp/stream_with_context/venv/lib/python3.12/site-packages/flask/app.py", line 1527, in wsgi_app
    ctx.pop(error)
  File "/private/tmp/stream_with_context/venv/lib/python3.12/site-packages/flask/ctx.py", line 418, in pop
    _cv_request.reset(token)
ValueError: <Token var=<ContextVar name='flask.request_ctx' at 0x1029ccea0> at 0x1049e1980> was created in a different Context

If the route is defined def foo(): without async, then this works without issue.

Or if we remove stream_with_context and just return Response(gen()), also works.

But the combination of async + stream_with_context fails.

There's also no issue with e.g. flask 2.1.0; I believe this was introduced in flask 2.2.0, specifically by #4682.

Environment:

  • Python version: 3.12.11
  • Flask version: 3.1.1

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions