Vercel python function error: `RuntimeError: Event loop is closed`

Here’s my python fastapi code:

PDF_MIME_TYPE = "application/pdf"


@api_router.get(
    "/download_pdf",
    response_class=StreamingResponse,
    responses={200: {"content": {PDF_MIME_TYPE: {}}}},
)
async def download_pdf():
    try:
        markdown = await get_answers()
        pdf_stream = BytesIO()
        pdf_report(markdown, pdf_stream)
        headers = {"Content-Disposition": 'attachment; filename="out.pdf"'}
        pdf_stream.seek(0)

        return StreamingResponse(pdf_stream, headers=headers, media_type=PDF_MIME_TYPE)
    except Exception as e:
        logging.exception("Error downloading PDF")
        return f"error: {e}"


app.include_router(api_router)

It’s working very well in my local environment. But when I deployed on Vercel, it often shows: RuntimeError: Event loop is closed, just when I access my link a little fast.

Here’s the error log:

INFO:httpx:HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent "HTTP/1.1 200 OK"
INFO:httpx:HTTP Request: POST https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent "HTTP/1.1 200 OK"
127.0.0.1 - - [18/Dec/2024 10:14:25] "GET /api/download_pdf?path=download_pdf HTTP/1.1" 200 -
it wrap_app_handling_exceptions(app, request)(scope, receive, send)
File "/var/task/starlette/_exception_handler.py", line 53, in wrapped_app
raise exc
File "/var/task/starlette/_exception_handler.py", line 42, in wrapped_app
await app(scope, receive, sender)
File "/var/task/starlette/routing.py", line 73, in app
response = await f(request)
^^^^^^^^^^^^^^^^
File "/var/task/fastapi/routing.py", line 301, in app
raw_response = await run_endpoint_function(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/fastapi/routing.py", line 212, in run_endpoint_function
return await dependant.call(**values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/api/index.py", line 22, in download_pdf
markdown = await get_answers()
^^^^^^^^^^^^^^^^^^^
File "/var/task/api/deep_thinking.py", line 171, in get_answers
questions = (await reader.run(article)).data
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/pydantic_ai/agent.py", line 251, in run
model_response, request_cost = await agent_model.request(messages, model_settings)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/pydantic_ai/models/gemini.py", line 176, in request
async with self._make_request(messages, False, model_settings) as http_response:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/lang/lib/python3.12/contextlib.py", line 210, in __aenter__
return await anext(self.gen)
^^^^^^^^^^^^^^^^^^^^^
File "/var/task/pydantic_ai/models/gemini.py", line 222, in _make_request
async with self.http_client.stream(
^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/lang/lib/python3.12/contextlib.py", line 210, in __aenter__
return await anext(self.gen)
^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1628, in stream
response = await self.send(
^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1674, in send
response = await self._send_handling_auth(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1702, in _send_handling_auth
response = await self._send_handling_redirects(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1739, in _send_handling_redirects
response = await self._send_single_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_client.py", line 1776, in _send_single_request
response = await transport.handle_async_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpx/_transports/default.py", line 377, in handle_async_request
resp = await self._pool.handle_async_request(req)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/var/task/httpcore/_async/connection_pool.py", line 256, in handle_async_request
raise exc from None
File "/var/task/httpcore/_async/connection_pool.py", line 229, in handle_async_request
await self._close_connections(closing)
File "/var/task/httpcore/_async/connection_pool.py", line 345, in _close_connections
await connection.aclose()
File "/var/task/httpcore/_async/connection.py", line 173, in aclose
await self._connection.aclose()
File "/var/task/httpcore/_async/http11.py", line 258, in aclose
await self._network_stream.aclose()
File "/var/task/httpcore/_backends/anyio.py", line 53, in aclose
await self._stream.aclose()
File "/var/task/anyio/streams/tls.py", line 201, in aclose
await self.transport_stream.aclose()
File "/var/task/anyio/_backends/_asyncio.py", line 1349, in aclose
self._transport.close()
File "/var/lang/lib/python3.12/asyncio/selector_events.py", line 1210, in close
super().close()
File "/var/lang/lib/python3.12/asyncio/selector_events.py", line 875, in close
self._loop.call_soon(self._call_connection_lost, None)
File "/var/lang/lib/python3.12/asyncio/base_events.py", line 795, in call_soon
self._check_closed()
File "/var/lang/lib/python3.12/asyncio/base_events.py", line 541, in _check_closed
raise RuntimeError('Event loop is closed')
RuntimeError: Event loop is closed
----------------------------------------

I guess this might be the same issue as: Python ASGI runtime creates an event loop on each request · Issue #8477 · vercel/vercel · GitHub but I’m not sure.

Anyone can help?

Thanks.

Hey @abcfy2. Would you be able to share a minimal reproducible example? That would give the rest of us a clearer view of how the project is configured

Hi @amyegan . Thanks.

Here’s the sample: GitHub - abcfy2/vercel-python-test

You can use vercel --prod to deploy this project.

The required environment variable GEMINI_API_KEY can be applied from Obtenir une clé API Gemini  |  Gemini API  |  Google AI for Developers . It’s free.

Then use curl to request twice fast, then you’ll see the error in vercel log:

cuirl -v --compressed "https://<your_vercel_domain>/api"

But I don’t know why I can’t see the error stack at the beginning. Only after triggering such errors many times in succession can I see the error stack in the vercel log. Like this:

You can follow the README.md to run locally, it’s working very well.

Please help.

Thanks.

Any updates?


any updates?