falcon: Websocket handler fails in some cases of HTTPError/HTTPStatus

Hi,

Writing ASGI falcon using websockets, using the process_request_ws middleware handler and app.add_error_handler(HTTPError, my_error_handler) error handler.

When raising a falcon.HTTPError in the middleware its picked up by the error handler via the ex param. The object is not none, however this is my stacktrace:

I raise the “falcon.http_error.HTTPError: <HTTPError: 403 Forbidden>” in the middleware, and then raise the “falcon.http_error.HTTPError: <HTTPError: 500>” in the error handler, which results in the final traceback (falcon internal).

'''
[2023-03-29 13:39:47 +0200] [82450] [INFO] ('127.0.0.1', 57224) - "WebSocket /message" 403
[2023-03-29 13:39:47 +0200] [82450] [ERROR] Exception in ASGI application
Traceback (most recent call last):
  File ".pyenv/versions/wm/lib/python3.11/site-packages/falcon/asgi/app.py", line 1000, in _handle_websocket
    await process_request_ws(req, web_socket)
  File "Desktop/mirror/whatsapp-service/whatsapp_service/middleware/basic_ws_middleware.py", line 106, in process_request_ws
    raise HTTPError(status=falcon.HTTP_403, title="Invalid header")
falcon.http_error.HTTPError: <HTTPError: 403 Forbidden>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File ".pyenv/versions/wm/lib/python3.11/site-packages/falcon/asgi/app.py", line 1095, in _handle_exception
    await err_handler(req, resp, ex, params, **kwargs)
  File "Desktop/mirror/whatsapp-service/whatsapp_service/utils/handlers/error_handlers.py", line 24, in my_error_handler
    raise HTTPError(status=500, title='Custom Websocket Error')
falcon.http_error.HTTPError: <HTTPError: 500>

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File ".pyenv/versions/wm/lib/python3.11/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 238, in run_asgi
    result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".pyenv/versions/wm/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__
    return await self.app(scope, receive, send)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".pyenv/versions/wm/lib/python3.11/site-packages/falcon/asgi/app.py", line 312, in __call__
    await self._handle_websocket(spec_version, scope, receive, send)
  File ".pyenv/versions/wm/lib/python3.11/site-packages/falcon/asgi/app.py", line 1018, in _handle_websocket
    if not await self._handle_exception(req, None, ex, params, ws=web_socket):
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".pyenv/versions/wm/lib/python3.11/site-packages/falcon/asgi/app.py", line 1100, in _handle_exception
    self._compose_error_response(req, resp, error)
  File "falcon/app.py", line 975, in falcon.app.App._compose_error_response
'''

The usage of the method resolution order is incorrect here as the type(exc) invocation returns type not the exception: https://github.com/falconry/falcon/blob/18503813059e648c693d03064adf2acdbe68d654/falcon/app.py#L1001

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 18 (10 by maintainers)

Most upvoted comments

btw thanks @sashn-citiqprepaid for supplying a complete example that reproduced your issue

I don’t think so.

The issue is that error raised in error handlers when using websockets were not correctly considered by falcon, so we try to serialize it on the a response object that missing since it’s a websocket response.

A workaround is to instead of raising the error in the error handler, to close the websocket if the websocket object is provided to the handler

Hi @vytas7 .

It might be my implementation that is unexpected, but worth exploring. Will put together an example.