Panel RuntimeError with FastAPI when using Templates

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.