diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e0404e123..e607f93487 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ### Fixed - [#3805](https://github.com/plotly/dash/pull/3805) Fix FastAPI POST routes deadlock caused by middleware consuming request body. Fixes [#3801](https://github.com/plotly/dash/issues/3801). +- [#3819](https://github.com/plotly/dash/pull/3819) Fix `RuntimeError: No active request in context` when a non-Dash path falls through to the FastAPI catch-all route. Fixes [#3812](https://github.com/plotly/dash/issues/3812). ## [4.2.0] - 2026-06-01 - *The Freedom Update* diff --git a/dash/backends/_fastapi.py b/dash/backends/_fastapi.py index 0516b5edcb..ed2693fb17 100644 --- a/dash/backends/_fastapi.py +++ b/dash/backends/_fastapi.py @@ -334,8 +334,12 @@ def _setup_catchall(self): try: dash_app = get_app() - async def catchall(_request: Request): - return Response(content=dash_app.index(), media_type="text/html") + async def catchall(request: Request): + token = set_current_request(request) + try: + return Response(content=dash_app.index(), media_type="text/html") + finally: + reset_current_request(token) # pylint: disable=protected-access self.add_url_rule("{path:path}", catchall, methods=["GET"]) diff --git a/tests/backend_tests/test_preconfig_backends.py b/tests/backend_tests/test_preconfig_backends.py index 5f912415ab..2e4b28ea1c 100644 --- a/tests/backend_tests/test_preconfig_backends.py +++ b/tests/backend_tests/test_preconfig_backends.py @@ -334,3 +334,22 @@ async def echo_post(request: Request): ) assert resp.status_code == 200 assert resp.json() == {"echo": {"hello": "world"}} + + +def test_fastapi_catchall_request_context(dash_duo): + """Test that non-Dash paths falling through to the catch-all route work. + + Regression test for https://github.com/plotly/dash/issues/3812 + The catch-all route renders ``dash_app.index()``, which needs a request + context; without it the request raised ``RuntimeError: No active request in + context`` and returned a 500. + """ + import requests + + app = Dash(__name__, backend="fastapi") + app.layout = html.Div("Dash is running") + + dash_duo.start_server(app) + + resp = requests.get(f"{dash_duo.server_url}/some/non-dash/path", timeout=5) + assert resp.status_code == 200