Fastapi: Unexpected ASGI message 'websocket.send', after sending 'websocket.close'.

Created on 18 Nov 2020  路  4Comments  路  Source: tiangolo/fastapi

Hi,
I am just connecting the users to websocket and returning the list of all connected users.

When i connect the first user everything works fine. But once i connect another user I get the following error:

Traceback (most recent call last):
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 154, in run_asgi
    result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/fastapi/applications.py", line 179, in __call__
    await super().__call__(scope, receive, send)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/starlette/applications.py", line 111, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/starlette/middleware/errors.py", line 146, in __call__
    await self.app(scope, receive, send)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/starlette/exceptions.py", line 58, in __call__
    await self.app(scope, receive, send)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/starlette/routing.py", line 566, in __call__
    await route.handle(scope, receive, send)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/starlette/routing.py", line 283, in handle
    await self.app(scope, receive, send)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/starlette/routing.py", line 57, in app
    await func(session)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/fastapi/routing.py", line 228, in app
    await dependant.call(**values)
  File "./main.py", line 110, in connect_user
    await socket_manager.get_online_users()
  File "./users/views.py", line 224, in get_online_users
    await connection[0].send_json({"sender": response.get('sender')})
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/starlette/websockets.py", line 137, in send_json
    await self.send({"type": "websocket.send", "text": text})
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/starlette/websockets.py", line 68, in send
    await self._send(message)
  File "/home/ahtisham/ENVS/ENV_COLLAB/lib/python3.8/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 231, in asgi_send
    raise RuntimeError(msg % message_type)
RuntimeError: Unexpected ASGI message 'websocket.send', after sending 'websocket.close'.

I found this issue but that doesn't work in my case.

websocket manager:

class SocketManager:
    def __init__(self):
        self.active_connections: List[(WebSocket, models.User)] = []

    async def connect(self, websocket: WebSocket, user: models.User):
        await websocket.accept()
        self.active_connections.append((websocket, user))

    async def get_online_users(self):
        response = {"receivers": []}
        for connection in self.active_connections:
            response['receivers'].append(connection[1].username)

        for connection in self.active_connections:
            response.update({"sender": connection[1].username})
            # this is causing the problem
            await connection[0].send_json(response)

websocket endpoint

socket_manager = SocketManager()

@app.websocket("/api/user-connect")
async def connect_user(websocket: views.WebSocket, db: Session = Depends(get_db)):
    user = views.get_current_user(db, websocket.cookies.get("access_token"))
    if user:
         # connect user to a websocket
        await socket_manager.connect(websocket, user)
        # broadcast the connected list of users.
        await socket_manager.get_online_users()

JavaScript code:

var socket = new WebSocket("ws://127.0.0.1:8000/api/user-connect");
socket.onmessage = function(event) {
        var data = JSON.parse(event.data);
        var sender = data['sender'];
        console.log(sender);              
}
question

Most helpful comment

If I had to guess, I'd say after your connect_user function exits, your websocket closes, so your socket manager just tries to send messages to closed sockets.

You probably want a loop recieving messages at the end of it instead

All 4 comments

Are you using python for connecting the two users to the websocket endpoint? If so please post this code as well.

I have seen similar issues when my client did not send the appropriate websocket "ping"s for the server to "pong", a keep alive mechanism used to make sure a client still exists so the connection does not close.

@codemation I am using javascript to create a websocket on frontend please check question i edited it.

If I had to guess, I'd say after your connect_user function exits, your websocket closes, so your socket manager just tries to send messages to closed sockets.

You probably want a loop recieving messages at the end of it instead

@Mause This fixed the problem :)

@app.websocket("/api/user-connect")
async def connect_user(websocket: views.WebSocket, db: Session = Depends(get_db)):
    user = views.get_current_user(db, websocket.cookies.get("access_token"))
    if user:
        await socket_manager.connect(websocket, user)
        await socket_manager.get_online_users()
        try:
            while True:
                data = await websocket.receive_json()
                print(data)
        except WebSocketDisconnect:
            socket_manager.disconnect(websocket, user)
Was this page helpful?
0 / 5 - 0 ratings