python-websockets / websockets

Library for building WebSocket servers and clients in Python

Home Page:https://websockets.readthedocs.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AttributeError: 'WebSocketProtocol' object has no attribute 'transfer_data_task'

ondrejchmelar opened this issue · comments

When the client disconnects just after setting self.application_state = WebSocketState.CONNECTED, subsequent ws.close() will fail at .venv/lib/python3.11/site-packages/websockets/legacy/protocol.py:784 as transfer_data_task will not be set up.

I suppose it should be guarded by if hasattr(self, "transfer_data_task"): as it is in other places.

Thank you for your report.

It shouldn't be possible to reach this line in close() before connection_open() completes successfully. I'd like to understand why this happens and, if applicable, to fix the root cause rather than just patch the symptom.

Could you provide a bit more details, please?

  1. Can you confirm that you talking about a client implemented with websockets?
  2. Can you provide the full stack trace? Ideally, debug logs too? (See https://websockets.readthedocs.io/en/stable/topics/logging.html#configure-logging)
  3. Do you have a minimum example that produces this behavior?

+1 here:

2024-05-01 10:11:59,863 - ERROR    - Task-368  - uvicorn/protocols/websockets/websockets_impl.py - run_asgi             - Exception in ASGI application

Traceback (most recent call last):
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 240, in run_asgi
    result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/uvicorn/middleware/proxy_headers.py", line 69, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/fastapi/applications.py", line 1054, in __call__
    await super().__call__(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/applications.py", line 123, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/middleware/errors.py", line 151, in __call__
    await self.app(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/middleware/cors.py", line 77, in __call__
    await self.app(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/middleware/exceptions.py", line 65, in __call__
    await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 756, in __call__
    await self.middleware_stack(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 776, in app
    await route.handle(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 373, in handle
    await self.app(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 96, in app
    await wrap_app_handling_exceptions(app, session)(scope, receive, send)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 64, in wrapped_app
    raise exc
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 53, in wrapped_app
    await app(scope, receive, sender)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/routing.py", line 94, in app
    await func(session)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/fastapi/routing.py", line 348, in app
    await dependant.call(**values)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/src/myapp_backend/api_v1/routes/device.py", line 68, in websocket_endpoint  # this is my application
    async with ws_connection(ws, serial, timeout=1) as messages:
  File "/usr/lib64/python3.12/contextlib.py", line 217, in __aexit__
    await anext(self.gen)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/src/myapp_backend/api_v1/routes/websocket.py", line 80, in ws_connection
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/websockets.py", line 203, in close
    await self.send(
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/websockets.py", line 97, in send
    await self._send(message)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/starlette/_exception_handler.py", line 50, in sender
    await send(message)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib/python3.12/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 337, in asgi_send
    await self.close(code, reason)
  File "/data/myapp-yocto/myapp-appl/myapp-backend/.venv/lib64/python3.12/site-packages/websockets/legacy/protocol.py", line 788, in close
    await self.transfer_data_task
          ^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'WebSocketProtocol' object has no attribute 'transfer_data_task'. Did you mean: 'transfer_data_exc'?

The issue occured while doing some evil concurrent load/abort/reload clicking of a Javascript/Vue.js-based page connecting to my websocket using the vueuse useWebsocket composable. See https://vueuse.org/core/useWebSocket/ for details of the client.