question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

TypeError when connection is closed in connect()

See original GitHub issue

I have the same problem then #185 but I think, I can reproduce it.

When you close a connection in the connect() method of a WebsocketConsumer, it works fine with daphne but uvicorn raises a TypeError

Traceback (most recent call last):
  File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 140, in run_asgi
    result = await asgi(self.asgi_receive, self.asgi_send)
  File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/sessions.py", line 179, in __call__
    return await self.inner(receive, self.send)
  File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/middleware.py", line 41, in coroutine_call
    await inner_instance(receive, send)
  File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/consumer.py", line 59, in __call__
    [receive, self.channel_receive], self.dispatch
  File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/utils.py", line 59, in await_many_dispatch
    await task
  File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/channels/utils.py", line 51, in await_many_dispatch
    result = task.result()
  File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 222, in asgi_receive
    data = await self.recv()
  File "/home/ossi/src/channels-examples/.venv/lib/python3.7/site-packages/websockets/protocol.py", line 419, in recv
    return_when=asyncio.FIRST_COMPLETED,
  File "/usr/lib/python3.7/asyncio/tasks.py", line 361, in wait
    fs = {ensure_future(f, loop=loop) for f in set(fs)}
  File "/usr/lib/python3.7/asyncio/tasks.py", line 361, in <setcomp>
    fs = {ensure_future(f, loop=loop) for f in set(fs)}
  File "/usr/lib/python3.7/asyncio/tasks.py", line 592, in ensure_future
    raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitable is required

I created this branch on the django-channels-example repository: https://github.com/ostcar/channels-examples/tree/uvicorn-test

All I changed was, that the websocket connection is always closed: https://github.com/andrewgodwin/channels-examples/compare/master...ostcar:uvicorn-test

I think the problem is, that you call websockets.WebSocketServerProtocol.recv() before the websocket connection is open so websockets.WebSocketServerProtocol.connection_open() was not called. In this case the attribute transfer_data_task is still None. So when websockets.WebSocketServerProtocol.recv() calls

yield from asyncio.wait(
                    [pop_message_waiter, self.transfer_data_task],
                    loop=self.loop,
                    return_when=asyncio.FIRST_COMPLETED,
                )

it tries to await None what causes the exception.

I don’t know, if this is a but in the websockets package or if you should check self.closed before calling self.recv()

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:7
  • Comments:18 (8 by maintainers)

github_iconTop GitHub Comments

5reactions
adamhoopercommented, Sep 8, 2020

If anyone’s able to reduce the issue like that then I’d be very happy to dig into it.

@tomchristie ping? I have reduced the issue by enabling logging in Uvicorn’s own test suite. I also submitted pull request #704 with a sketch of a fix. Are you still keen to dig into it? 😃

5reactions
ostcarcommented, Apr 13, 2019

Here is a minimal example without using django:

class Application:
    def __init__(self, scope):
        self.scope = scope

    async def __call__(self, receive, send):
        if self.scope["type"] != "websocket":
            return

        while True:
            # what for the 'websocket.connect' event.
            await receive()

            # Close the connection
            await send({'type': 'websocket.close'})

To test it, you have to start it with an asgi server an open a websocket connection.

With daphne:

$ daphne asgi:Application
2019-04-13 23:49:51,867 INFO     Starting server at tcp:port=8000:interface=127.0.0.1
2019-04-13 23:49:51,867 INFO     HTTP/2 support not enabled (install the http2 and tls Twisted extras)
2019-04-13 23:49:51,867 INFO     Configuring endpoint tcp:port=8000:interface=127.0.0.1
2019-04-13 23:49:51,868 INFO     Listening on TCP address 127.0.0.1:8000
127.0.0.1:58152 - - [13/Apr/2019:23:50:00] "WSCONNECTING /" - -
127.0.0.1:58152 - - [13/Apr/2019:23:50:00] "WSREJECT /" - -
127.0.0.1:58152 - - [13/Apr/2019:23:50:00] "WSDISCONNECT /" - -
^C2019-04-13 23:50:01,841 INFO     Killed 1 pending application instances

With uvicorn and websockets:

$ uvicorn asgi:Application --ws websockets
INFO: Started server process [23052]
INFO: Waiting for application startup.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: ('127.0.0.1', 58172) - "WebSocket /" 403
ERROR: Exception in ASGI application
Traceback (most recent call last):
  File "/home/ossi/src/uvicorn_test/venv/lib/python3.7/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 147, in run_asgi
    result = await asgi(self.asgi_receive, self.asgi_send)
  File "./asgi.py", line 12, in __call__
    await receive()
  File "/home/ossi/src/uvicorn_test/venv/lib/python3.7/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 227, in asgi_receive
    data = await self.recv()
  File "/home/ossi/src/uvicorn_test/venv/lib/python3.7/site-packages/websockets/protocol.py", line 419, in recv
    return_when=asyncio.FIRST_COMPLETED,
  File "/usr/lib/python3.7/asyncio/tasks.py", line 361, in wait
    fs = {ensure_future(f, loop=loop) for f in set(fs)}
  File "/usr/lib/python3.7/asyncio/tasks.py", line 361, in <setcomp>
    fs = {ensure_future(f, loop=loop) for f in set(fs)}
  File "/usr/lib/python3.7/asyncio/tasks.py", line 592, in ensure_future
    raise TypeError('An asyncio.Future, a coroutine or an awaitable is '
TypeError: An asyncio.Future, a coroutine or an awaitable is required
^CINFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Finished server process [23052]

With uvicorn and wsproto:

$ uvicorn asgi:Application --ws wsproto
INFO: Started server process [23092]
INFO: Waiting for application startup.
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: ('127.0.0.1', 58178) - "WebSocket /" 403
ERROR: Exception in ASGI application
Traceback (most recent call last):
  File "/home/ossi/src/uvicorn_test/venv/lib/python3.7/site-packages/uvicorn/protocols/websockets/wsproto_impl.py", line 208, in run_asgi
    result = await asgi(self.receive, self.send)
  File "./asgi.py", line 15, in __call__
    await send({'type': 'websocket.close'})
  File "/home/ossi/src/uvicorn_test/venv/lib/python3.7/site-packages/uvicorn/protocols/websockets/wsproto_impl.py", line 257, in send
    output = self.conn.send(msg)
  File "/home/ossi/src/uvicorn_test/venv/lib/python3.7/site-packages/wsproto/__init__.py", line 35, in send
    data += self.handshake.send(event)
  File "/home/ossi/src/uvicorn_test/venv/lib/python3.7/site-packages/wsproto/handshake.py", line 97, in send
    "Event {} cannot be sent during the handshake".format(event)
wsproto.utilities.LocalProtocolError: Event Response(status_code=403, headers=[], http_version=b'1.1', reason=b'') cannot be sent during the handshake
^CINFO: Shutting down
INFO: Waiting for application shutdown.
INFO: Finished server process [23092]

The error seems to be, that the while True: loop does not break. But when I look into the django channels code, it seems, that django channels also does not close the loop.

The loop in django channels is here: https://github.com/django/channels/blob/03d221792e6881477911728615a6d51ec9fab73b/channels/utils.py#L45

The close message is send here: https://github.com/django/channels/blob/03d221792e6881477911728615a6d51ec9fab73b/channels/generic/websocket.py#L226

An exception, that could break the loop is raised when websocket.disconnect is handled: https://github.com/django/channels/blob/03d221792e6881477911728615a6d51ec9fab73b/channels/generic/websocket.py#L241

Read more comments on GitHub >

github_iconTop Results From Across the Web

Dealing properly with closed connection with pymysql
I am making a class to unify the way we deal with the database and I want to make sure the connection is...
Read more >
Error Messages - SQLAlchemy 1.4 Documentation
The InternalError is sometimes raised by drivers in the context of the database connection being dropped, or not being able to connect to...
Read more >
Why do we get the error "Connection reset by peer ... - IBM
The error message "Connection reset by peer" appears, if the web services client ... remote web services provider and the connection was closed...
Read more >
ASP.NET Core SignalR JavaScript client - Microsoft Learn
Install the SignalR client package; Connect to a hub ... This can cause SignalR connections to close and may result in an unwanted...
Read more >
pika.connection — pika 1.2.1 documentation - Read the Docs
Real): raise TypeError('blocked_connection_timeout must be a Real ' 'number, ... as the result of Connection.close() call during # opening. self.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found