I’ve been trying to build a Panel app with FastAPI. The app renders fine, however if the web browser is refreshed I’m getting a RuntimeError (shown below). I’ve tried adding websocket handlers but not getting them to work. However, when the app is simplified and I don’t use the template, just the layout the issue is not longer there (refreshing the web page works fine, not RuntimeError). Is there a way to make the app work including the template and not getting the RuntimeError?.
import panel as pn
from fastapi import FastAPI
from panel.io.fastapi import add_application
import pandas as pd
import numpy as np
# Create FastAPI app instance
app = FastAPI()
@add_application('/hello', app=app, title='Hello World App')
def create_hello_app():
# Create a random DataFrame
df = pd.DataFrame(
np.random.randn(10, 4),
columns=['A', 'B', 'C', 'D']
).round(2)
# Create a tabulator widget with the DataFrame
table = pn.widgets.Tabulator(df, sizing_mode='stretch_width')
# Create the template
template = pn.template.FastListTemplate(
title='Simple Panel App',
sidebar=[
pn.pane.Markdown("# Hello World!")
],
main=[
pn.pane.Markdown("## Random Data Table"),
table
],
header_background='#00b3e3'
)
return template
I’m running the app with fastapi dev app.py
The RuntimeError is:
INFO: 127.0.0.1:49036 - "GET /hello HTTP/1.1" 200 OK
INFO: connection closed
INFO: ('127.0.0.1', 49046) - "WebSocket /hello/ws" [accepted]
INFO: connection open
Exception in callback functools.partial(<bound method IOLoop._discard_future_result of <tornado.platform.asyncio.AsyncIOMainLoop object at 0x7f02da8d1e10>>, <Task finished name='Task-38' coro=<ServerSession.with_document_locked() done, defined at /home/panelapp/.venv/lib/python3.10/site-packages/bokeh/server/session.py:77> exception=RuntimeError("Unexpected ASGI message 'websocket.send', after sending 'websocket.close' or response already completed.")>)
Traceback (most recent call last):
File "/home/panelapp/.venv/lib/python3.10/site-packages/tornado/ioloop.py", line 750, in _run_callback
ret = callback()
File "/home/panelapp/.venv/lib/python3.10/site-packages/tornado/ioloop.py", line 774, in _discard_future_result
future.result()
File "/home/panelapp/.venv/lib/python3.10/site-packages/bokeh/server/session.py", line 106, in _needs_document_lock_wrapper
await p
File "/home/panelapp/.venv/lib/python3.10/site-packages/bokeh_fastapi/handler.py", line 355, in send_message
await self._socket.send_text(message.header_json)
File "/home/panelapp/.venv/lib/python3.10/site-packages/starlette/websockets.py", line 165, in send_text
await self.send({"type": "websocket.send", "text": data})
File "/home/panelapp/.venv/lib/python3.10/site-packages/starlette/websockets.py", line 85, in send
await self._send(message)
File "/home/panelapp/.venv/lib/python3.10/site-packages/starlette/_exception_handler.py", line 39, in sender
await send(message)
File "/home/panelapp/.venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 358, in asgi_send
raise RuntimeError(msg % message_type)
RuntimeError: Unexpected ASGI message 'websocket.send', after sending 'websocket.close' or response already completed.
Exception in callback functools.partial(<bound method IOLoop._discard_future_result of <tornado.platform.asyncio.AsyncIOMainLoop object at 0x7f02da8d1e10>>, <Task finished name='Task-51' coro=<ServerSession.with_document_locked() done, defined at /home/panelapp/.venv/lib/python3.10/site-packages/bokeh/server/session.py:77> exception=RuntimeError("Unexpected ASGI message 'websocket.send', after sending 'websocket.close' or response already completed.")>)
Traceback (most recent call last):
File "/home/panelapp/.venv/lib/python3.10/site-packages/tornado/ioloop.py", line 750, in _run_callback
ret = callback()
File "/home/panelapp/.venv/lib/python3.10/site-packages/tornado/ioloop.py", line 774, in _discard_future_result
future.result()
File "/home/panelapp/.venv/lib/python3.10/site-packages/bokeh/server/session.py", line 106, in _needs_document_lock_wrapper
await p
File "/home/panelapp/.venv/lib/python3.10/site-packages/bokeh_fastapi/handler.py", line 355, in send_message
await self._socket.send_text(message.header_json)
File "/home/panelapp/.venv/lib/python3.10/site-packages/starlette/websockets.py", line 165, in send_text
await self.send({"type": "websocket.send", "text": data})
File "/home/panelapp/.venv/lib/python3.10/site-packages/starlette/websockets.py", line 85, in send
await self._send(message)
File "/home/panelapp/.venv/lib/python3.10/site-packages/starlette/_exception_handler.py", line 39, in sender
await send(message)
File "/home/panelapp/.venv/lib/python3.10/site-packages/uvicorn/protocols/websockets/websockets_impl.py", line 358, in asgi_send
raise RuntimeError(msg % message_type)
RuntimeError: Unexpected ASGI message 'websocket.send', after sending 'websocket.close' or response already completed.