Describe your context
dash 4.1.0rc0
fastapi 0.135.1
starlette 1.0.0rc1
uvicorn 0.41.0
- Python 3.13.0
- OS: macOS 15.5
Describe the bug
DashMiddleware.__call__ in dash/backends/_fastapi.py crashes when a WebSocket connection is made to the underlying FastAPI server. The middleware allows "websocket" scopes through its type filter (line 187) but then unconditionally creates a Starlette Request(scope, receive=receive) on line 192. Starlette's Request.__init__ asserts scope["type"] == "http", so any WebSocket scope raises an AssertionError.
This prevents using FastAPI's native @app.server.websocket() decorator alongside Dash.
The relevant code in DashMiddleware.__call__:
# Non-HTTP/WebSocket scopes pass throughifscope["type"] notin ("http", "websocket"):
awaitself.app(scope, receive, send)
return# HTTP/WebSocket request handlingrequest=Request(scope, receive=receive) # crashes for websocket scopesThe comment says "pass through" for non-HTTP/WebSocket, but WebSocket scopes should also pass through since Request() only supports HTTP.
Expected behavior
WebSocket connections to custom FastAPI endpoints should work without crashing. The middleware should either pass WebSocket scopes through to the underlying ASGI app, or handle them with the appropriate Starlette WebSocket class instead of Request.
Suggested fix
Either change the guard to only process HTTP scopes:
ifscope["type"] !="http":
awaitself.app(scope, receive, send)
return
Or, if the middleware needs to handle WebSocket scopes in the future, use WebSocket(scope, receive=receive, send=send) for websocket types.
Reproduction
importdashfromdashimporthtmlfromfastapiimportWebSocket, WebSocketDisconnectapp=dash.Dash(__name__, backend="fastapi")
app.layout=html.Div("Hello")
@app.server.websocket("/ws")asyncdefws_endpoint(websocket: WebSocket):
awaitwebsocket.accept()
awaitwebsocket.send_json({"msg": "hello"})
awaitwebsocket.close()
if__name__=="__main__":
app.run(debug=True, port=8050)Connect with any WebSocket client → AssertionError inside Starlette's Request.__init__.
Workaround
Monkey-patch the middleware to pass WebSocket scopes straight through:
fromdash.backends._fastapiimportDashMiddleware_original_call=DashMiddleware.__call__asyncdef_patched_call(self, scope, receive, send):
ifscope["type"] =="websocket":
awaitself.app(scope, receive, send)
returnreturnawait_original_call(self, scope, receive, send)
DashMiddleware.__call__=_patched_call
Describe your context
Describe the bug
DashMiddleware.__call__indash/backends/_fastapi.pycrashes when a WebSocket connection is made to the underlying FastAPI server. The middleware allows"websocket"scopes through its type filter (line 187) but then unconditionally creates a StarletteRequest(scope, receive=receive)on line 192. Starlette'sRequest.__init__assertsscope["type"] == "http", so any WebSocket scope raises anAssertionError.This prevents using FastAPI's native
@app.server.websocket()decorator alongside Dash.The relevant code in
DashMiddleware.__call__:The comment says "pass through" for non-HTTP/WebSocket, but WebSocket scopes should also pass through since
Request()only supports HTTP.Expected behavior
WebSocket connections to custom FastAPI endpoints should work without crashing. The middleware should either pass WebSocket scopes through to the underlying ASGI app, or handle them with the appropriate Starlette
WebSocketclass instead ofRequest.Suggested fix
Either change the guard to only process HTTP scopes:
Or, if the middleware needs to handle WebSocket scopes in the future, use
WebSocket(scope, receive=receive, send=send)for websocket types.Reproduction
Connect with any WebSocket client →
AssertionErrorinside Starlette'sRequest.__init__.Workaround
Monkey-patch the middleware to pass WebSocket scopes straight through: