Skip to content

[BUG]: Fastapi page routes trigger 500 internal server error #3834

@joschrag

Description

@joschrag

Thank you so much for helping improve the quality of Dash!

We do our best to catch bugs during the release process, but we rely on your help to find the ones that slip through.

Describe your context
Please provide us your environment, so we can easily reproduce the issue.

dash                 4.3.0

Describe the bug

When creating a simple dash app with fastapi backend like this:

app.py

import dash
from dash import Dash, html

app = Dash(__name__, backend="fastapi", use_pages=True)
app.layout = html.Div([html.H1("MWE"), dash.page_container])

if __name__ == "__main__":
    app.run()

pages/index.py

import dash
from dash import html

dash.register_page(__name__, path="/", layout=html.Div("home"))

pages/home.py

import dash
from dash import html

dash.register_page(__name__, path="/home", layout=html.Div("home"))

When browsing these pages or with curl we get the following:

curl -w "%{http_code}" -o NUL -s http://127.0.0.1:8050/ -> 200
curl -w "%{http_code}" -o NUL -s http://127.0.0.1:8050/home -> 500

with the traceback:

Traceback (most recent call last):
  File "...\uvicorn\protocols\http\httptools_impl.py", line 421, in run_asgi
    result = await app(  # type: ignore[func-returns-value]
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\uvicorn\middleware\proxy_headers.py", line 62, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\fastapi\applications.py", line 1159, in __call__
    await super().__call__(scope, receive, send)
  File "...\starlette\applications.py", line 90, in __call__
    await self.middleware_stack(scope, receive, send)
  File "...\starlette\middleware\errors.py", line 186, in __call__
    raise exc
  File "...\starlette\middleware\errors.py", line 164, in __call__
    await self.app(scope, receive, _send)
  File "...\dash\backends\_fastapi.py", line 235, in __call__
    await self.app(scope, receive, send)
  File "...\starlette\middleware\exceptions.py", line 63, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "...\starlette\_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "...\starlette\_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "...\fastapi\middleware\asyncexitstack.py", line 18, in __call__
    await self.app(scope, receive, send)
  File "...\starlette\routing.py", line 660, in __call__
    await self.middleware_stack(scope, receive, send)
  File "...\starlette\routing.py", line 680, in app
    await route.handle(scope, receive, send)
  File "...\starlette\routing.py", line 276, in handle
    await self.app(scope, receive, send)
  File "...\fastapi\routing.py", line 134, in app
    await wrap_app_handling_exceptions(app, request)(scope, receive, send)
  File "...\starlette\_exception_handler.py", line 53, in wrapped_app
    raise exc
  File "...\starlette\_exception_handler.py", line 42, in wrapped_app
    await app(scope, receive, sender)
  File "...\fastapi\routing.py", line 120, in app
    response = await f(request)
               ^^^^^^^^^^^^^^^^
  File "...\fastapi\routing.py", line 674, in app
    raw_response = await run_endpoint_function(
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\fastapi\routing.py", line 328, in run_endpoint_function
    return await dependant.call(**values)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\dash\backends\_fastapi.py", line 338, in catchall
    return Response(content=dash_app.index(), media_type="text/html")
                            ^^^^^^^^^^^^^^^^
  File "...\dash\dash.py", line 1302, in index
    request = self.backend.request_adapter()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "...\dash\backends\_fastapi.py", line 842, in __init__
    self._request: Request = get_current_request()
                             ^^^^^^^^^^^^^^^^^^^^^
  File "...\dash\backends\_fastapi.py", line 109, in get_current_request
    raise RuntimeError("No active request in context")
RuntimeError: No active request in context

#3805 seems to be the cause as the /home route does not match any conditions and exits before the request context is set in dash/backends/_fastapi.py

async def __call_():
...

    if (
            not path.startswith(dash_prefix)
            and path != prefix
            and path != prefix.rstrip("/")
        ):
            await self.app(scope, receive, send)  # /home fails within here
            return
    
    request = Request(scope, receive=receive)
    token = set_current_request(request)
...

Expected behavior

The /home path should return a 200 Response and its content.

Screenshots

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions